Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 5/7] ARM: brcmstb: add misc. DT bindings for brcm, brcmstb-*
From: Marc Carino @ 2014-01-14 23:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1389743333-16741-1-git-send-email-marc.ceeeee@gmail.com>

Document the bindings that the Broadcom STB platform needs
for proper bootup.

Signed-off-by: Marc Carino <marc.ceeeee@gmail.com>
Acked-by: Florian Fainelli <f.fainelli@gmail.com>
---
 .../devicetree/bindings/arm/brcm-brcmstb.txt       |   43 ++++++++++++++++++++
 1 files changed, 43 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/brcm-brcmstb.txt

diff --git a/Documentation/devicetree/bindings/arm/brcm-brcmstb.txt b/Documentation/devicetree/bindings/arm/brcm-brcmstb.txt
new file mode 100644
index 0000000..5f1aba7
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/brcm-brcmstb.txt
@@ -0,0 +1,43 @@
+Broadcom STB platforms Device Tree Bindings
+-------------------------------------------
+Boards with Broadcom Brahma15 ARM-based BCM7xxx SoC shall have the following
+properties.
+
+Required root node properties:
+
+    - compatible = "brcm,brcmstb-<chip_id>";
+
+Further, a node with the following compatible string shall be defined:
+
+    - compatible: "brcm,brcmstb-gen-ctrl-v1"
+
+brcmstb-gen-ctrl
+----------------
+This node describes the registers needed for reset and CPU power control.
+
+    - compatible: "brcm,brcmstb-gen-ctrl-v1"
+    - properties:
+        o reg = <rst-src-en-reg-base len
+                 sw-mstr-rst-reg-base len
+                 cpu-rst-cfg-reg-base len
+                 cpu-pwr-zone-ctrl-reg-base len
+                 stb-boot-hi-addr0-reg len>;
+
+example:
+/ {
+    model = "Broadcom STB";
+    compatible =  "brcm,brcmstb-7445";
+
+    /* snip */
+
+    gen-ctrl {
+        compatible = "brcm,brcmstb-gen-ctrl-v1";
+        reg = <0xf0404304 0x4
+               0xf0404308 0x4
+               0xf03e2578 0x4
+               0xf03e2488 0x10
+               0xf0452000 0x20>;
+    };
+
+    /* snip */
+};
-- 
1.7.1

^ permalink raw reply related

* [PATCH v3 4/7] ARM: brcmstb: add CPU binding for Broadcom Brahma15
From: Marc Carino @ 2014-01-14 23:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1389743333-16741-1-git-send-email-marc.ceeeee@gmail.com>

Add the Broadcom Brahma B15 CPU to the DT CPU binding list.

Signed-off-by: Marc Carino <marc.ceeeee@gmail.com>
Acked-by: Florian Fainelli <f.fainelli@gmail.com>
---
 Documentation/devicetree/bindings/arm/cpus.txt |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt
index 9130435..423b879 100644
--- a/Documentation/devicetree/bindings/arm/cpus.txt
+++ b/Documentation/devicetree/bindings/arm/cpus.txt
@@ -163,6 +163,7 @@ nodes to be present and contain the properties described below.
 			    "arm,cortex-r4"
 			    "arm,cortex-r5"
 			    "arm,cortex-r7"
+			    "brcm,brahma15"
 			    "faraday,fa526"
 			    "intel,sa110"
 			    "intel,sa1100"
-- 
1.7.1

^ permalink raw reply related

* [PATCH v3 3/7] ARM: do CPU-specific init for Broadcom Brahma15 cores
From: Marc Carino @ 2014-01-14 23:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1389743333-16741-1-git-send-email-marc.ceeeee@gmail.com>

Perform any CPU-specific initialization required on the
Broadcom Brahma-15 core.

Signed-off-by: Marc Carino <marc.ceeeee@gmail.com>
Acked-by: Florian Fainelli <f.fainelli@gmail.com>
---
 arch/arm/mm/proc-v7.S |   11 +++++++++++
 1 files changed, 11 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index bd17819..98ea423 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -193,6 +193,7 @@ __v7_cr7mp_setup:
 	b	1f
 __v7_ca7mp_setup:
 __v7_ca15mp_setup:
+__v7_b15mp_setup:
 	mov	r10, #0
 1:
 #ifdef CONFIG_SMP
@@ -494,6 +495,16 @@ __v7_ca15mp_proc_info:
 	.size	__v7_ca15mp_proc_info, . - __v7_ca15mp_proc_info
 
 	/*
+	 * Broadcom Corporation Brahma-B15 processor.
+	 */
+	.type	__v7_b15mp_proc_info, #object
+__v7_b15mp_proc_info:
+	.long	0x420f00f0
+	.long	0xff0ffff0
+	__v7_proc __v7_b15mp_setup, hwcaps = HWCAP_IDIV
+	.size	__v7_b15mp_proc_info, . - __v7_b15mp_proc_info
+
+	/*
 	 * Qualcomm Inc. Krait processors.
 	 */
 	.type	__krait_proc_info, #object
-- 
1.7.1

^ permalink raw reply related

* [PATCH v3 2/7] ARM: brcmstb: add debug UART for earlyprintk support
From: Marc Carino @ 2014-01-14 23:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1389743333-16741-1-git-send-email-marc.ceeeee@gmail.com>

Add the UART definitions needed to support earlyprintk on brcmstb machines.

Signed-off-by: Marc Carino <marc.ceeeee@gmail.com>
Acked-by: Florian Fainelli <f.fainelli@gmail.com>
---
 arch/arm/Kconfig.debug |   16 +++++++++++++++-
 1 files changed, 15 insertions(+), 1 deletions(-)

diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 5765abf..266c699 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -94,6 +94,17 @@ choice
 		depends on ARCH_BCM2835
 		select DEBUG_UART_PL01X
 
+	config DEBUG_BRCMSTB_UART
+		bool "Use BRCMSTB UART for low-level debug"
+		depends on ARCH_BRCMSTB
+		select DEBUG_UART_8250
+		help
+		  Say Y here if you want the debug print routines to direct
+		  their output to the first serial port on these devices.
+
+		  If you have a Broadcom STB chip and would like early print
+		  messages to appear over the UART, select this option.
+
 	config DEBUG_CLPS711X_UART1
 		bool "Kernel low-level debugging messages via UART1"
 		depends on ARCH_CLPS711X
@@ -988,6 +999,7 @@ config DEBUG_UART_PHYS
 	default 0x20064000 if DEBUG_RK29_UART1 || DEBUG_RK3X_UART2
 	default 0x20068000 if DEBUG_RK29_UART2 || DEBUG_RK3X_UART3
 	default 0x20201000 if DEBUG_BCM2835
+	default 0xf0406b00 if DEBUG_BRCMSTB_UART
 	default 0x4000e400 if DEBUG_LL_UART_EFM32
 	default 0x40090000 if ARCH_LPC32XX
 	default 0x40100000 if DEBUG_PXA_UART1
@@ -1029,6 +1041,7 @@ config DEBUG_UART_VIRT
 	default 0xf0009000 if DEBUG_CNS3XXX
 	default 0xf01fb000 if DEBUG_NOMADIK_UART
 	default 0xf0201000 if DEBUG_BCM2835
+	default 0xfc406b00 if DEBUG_BRCMSTB_UART
 	default 0xf11f1000 if ARCH_VERSATILE
 	default 0xf1600000 if ARCH_INTEGRATOR
 	default 0xf1c28000 if DEBUG_SUNXI_UART0
@@ -1091,7 +1104,8 @@ config DEBUG_UART_8250_WORD
 	default y if DEBUG_PICOXCELL_UART || DEBUG_SOCFPGA_UART || \
 		ARCH_KEYSTONE || \
 		DEBUG_DAVINCI_DMx_UART0 || DEBUG_DAVINCI_DA8XX_UART1 || \
-		DEBUG_DAVINCI_DA8XX_UART2 || DEBUG_DAVINCI_TNETV107X_UART1
+		DEBUG_DAVINCI_DA8XX_UART2 || DEBUG_DAVINCI_TNETV107X_UART1 || \
+		DEBUG_BRCMSTB_UART
 
 config DEBUG_UART_8250_FLOW_CONTROL
 	bool "Enable flow control for 8250 UART"
-- 
1.7.1

^ permalink raw reply related

* [PATCH v3 1/7] ARM: brcmstb: add infrastructure for ARM-based Broadcom STB SoCs
From: Marc Carino @ 2014-01-14 23:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1389743333-16741-1-git-send-email-marc.ceeeee@gmail.com>

The BCM7xxx series of Broadcom SoCs are used primarily in set-top boxes.

This patch adds machine support for the ARM-based Broadcom SoCs.

Signed-off-by: Marc Carino <marc.ceeeee@gmail.com>
Acked-by: Florian Fainelli <f.fainelli@gmail.com>
---
 arch/arm/configs/multi_v7_defconfig |    1 +
 arch/arm/mach-bcm/Kconfig           |   14 ++
 arch/arm/mach-bcm/Makefile          |    4 +
 arch/arm/mach-bcm/brcmstb.c         |  146 ++++++++++++++++++++
 arch/arm/mach-bcm/brcmstb.h         |   46 +++++++
 arch/arm/mach-bcm/headsmp-brcmstb.S |   34 +++++
 arch/arm/mach-bcm/hotplug-brcmstb.c |  252 +++++++++++++++++++++++++++++++++++
 7 files changed, 497 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-bcm/brcmstb.c
 create mode 100644 arch/arm/mach-bcm/brcmstb.h
 create mode 100644 arch/arm/mach-bcm/headsmp-brcmstb.S
 create mode 100644 arch/arm/mach-bcm/hotplug-brcmstb.c

diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig
index c1df4e9..7028d11 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -7,6 +7,7 @@ CONFIG_MACH_ARMADA_370=y
 CONFIG_MACH_ARMADA_XP=y
 CONFIG_ARCH_BCM=y
 CONFIG_ARCH_BCM_MOBILE=y
+CONFIG_ARCH_BRCMSTB=y
 CONFIG_GPIO_PCA953X=y
 CONFIG_ARCH_HIGHBANK=y
 CONFIG_ARCH_KEYSTONE=y
diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig
index 9fe6d88..2c1ae83 100644
--- a/arch/arm/mach-bcm/Kconfig
+++ b/arch/arm/mach-bcm/Kconfig
@@ -31,6 +31,20 @@ config ARCH_BCM_MOBILE
 	  BCM11130, BCM11140, BCM11351, BCM28145 and
 	  BCM28155 variants.
 
+config ARCH_BRCMSTB
+	bool "Broadcom BCM7XXX based boards" if ARCH_MULTI_V7
+	depends on MMU
+	select ARM_GIC
+	select MIGHT_HAVE_PCI
+	select HAVE_SMP
+	select HAVE_ARM_ARCH_TIMER
+	help
+	  Say Y if you intend to run the kernel on a Broadcom ARM-based STB
+	  chipset.
+
+	  This enables support for Broadcom ARM-based set-top box chipsets,
+	  including the 7445 family of chips.
+
 endmenu
 
 endif
diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile
index c2ccd5a..b744a12 100644
--- a/arch/arm/mach-bcm/Makefile
+++ b/arch/arm/mach-bcm/Makefile
@@ -13,3 +13,7 @@
 obj-$(CONFIG_ARCH_BCM_MOBILE)	:= board_bcm281xx.o bcm_kona_smc.o bcm_kona_smc_asm.o kona.o
 plus_sec := $(call as-instr,.arch_extension sec,+sec)
 AFLAGS_bcm_kona_smc_asm.o	:=-Wa,-march=armv7-a$(plus_sec)
+
+obj-$(CONFIG_ARCH_BRCMSTB)	:= brcmstb.o
+obj-$(CONFIG_SMP)		+= headsmp-brcmstb.o
+obj-$(CONFIG_HOTPLUG_CPU)	+= hotplug-brcmstb.o
diff --git a/arch/arm/mach-bcm/brcmstb.c b/arch/arm/mach-bcm/brcmstb.c
new file mode 100644
index 0000000..eb9de26
--- /dev/null
+++ b/arch/arm/mach-bcm/brcmstb.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2013 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/console.h>
+#include <linux/clocksource.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/printk.h>
+#include <linux/smp.h>
+
+#include <asm/cacheflush.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/time.h>
+
+#include "brcmstb.h"
+
+/***********************************************************************
+ * STB CPU (main application processor)
+ ***********************************************************************/
+
+static const char *brcmstb_match[] __initconst = {
+	"brcm,brcmstb-7445",
+	NULL
+};
+
+static void brcmstb_restart(enum reboot_mode mode, const char *cmd)
+{
+	struct device_node *np;
+	char *name;
+	void __iomem *rst_src_en;
+	void __iomem *sw_mstr_rst;
+
+	name = "brcm,brcmstb-gen-ctrl-v1";
+	np = of_find_compatible_node(NULL, NULL, name);
+	if (!np) {
+		pr_err("cannot find node %s\n", name);
+		return;
+	}
+
+	rst_src_en = of_iomap(np, GEN_CTRL_V1_RST_SRC_EN);
+	if (!rst_src_en) {
+		pr_err("can't iomap rst_src_en\n");
+		return;
+	}
+
+	sw_mstr_rst = of_iomap(np, GEN_CTRL_V1_SW_MSTR_RST);
+	if (!sw_mstr_rst) {
+		pr_err("can't iomap sw_mstr_rst\n");
+		return;
+	}
+
+	writel_relaxed(1, rst_src_en);
+	readl_relaxed(rst_src_en);
+
+	writel_relaxed(1, sw_mstr_rst);
+	readl_relaxed(sw_mstr_rst);
+
+	while (1)
+		;
+}
+
+static void __init brcmstb_init_early(void)
+{
+	add_preferred_console("ttyS", 0, "115200");
+}
+
+/***********************************************************************
+ * SMP boot
+ ***********************************************************************/
+
+#ifdef CONFIG_SMP
+static DEFINE_SPINLOCK(boot_lock);
+
+static void __cpuinit brcmstb_secondary_init(unsigned int cpu)
+{
+	/*
+	 * Synchronise with the boot thread.
+	 */
+	spin_lock(&boot_lock);
+	spin_unlock(&boot_lock);
+}
+
+static int __cpuinit brcmstb_boot_secondary(unsigned int cpu,
+					    struct task_struct *idle)
+{
+	/*
+	 * set synchronisation state between this boot processor
+	 * and the secondary one
+	 */
+	spin_lock(&boot_lock);
+
+	/* Bring up power to the core if necessary */
+	if (brcmstb_cpu_get_power_state(cpu) == 0)
+		brcmstb_cpu_power_on(cpu);
+
+	brcmstb_cpu_boot(cpu);
+
+	/*
+	 * now the secondary core is starting up let it run its
+	 * calibrations, then wait for it to finish
+	 */
+	spin_unlock(&boot_lock);
+
+	return 0;
+}
+
+struct smp_operations brcmstb_smp_ops __initdata = {
+	.smp_prepare_cpus	= brcmstb_cpu_ctrl_setup,
+	.smp_secondary_init	= brcmstb_secondary_init,
+	.smp_boot_secondary	= brcmstb_boot_secondary,
+#ifdef CONFIG_HOTPLUG_CPU
+	.cpu_kill		= brcmstb_cpu_kill,
+	.cpu_die		= brcmstb_cpu_die,
+#endif
+};
+#endif
+
+DT_MACHINE_START(BRCMSTB, "Broadcom STB (Flattened Device Tree)")
+	.dt_compat	= brcmstb_match,
+	.restart	= brcmstb_restart,
+#ifdef CONFIG_SMP
+	.smp		= smp_ops(brcmstb_smp_ops),
+#endif
+	.init_early	= brcmstb_init_early,
+MACHINE_END
diff --git a/arch/arm/mach-bcm/brcmstb.h b/arch/arm/mach-bcm/brcmstb.h
new file mode 100644
index 0000000..9012afb
--- /dev/null
+++ b/arch/arm/mach-bcm/brcmstb.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2013 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __BRCMSTB_H__
+#define __BRCMSTB_H__
+
+#if !defined(__ASSEMBLY__)
+#include <linux/smp.h>
+#endif
+
+#if !defined(__ASSEMBLY__)
+extern void brcmstb_secondary_startup(void);
+extern void brcmstb_cpu_boot(unsigned int cpu);
+extern void brcmstb_cpu_power_on(unsigned int cpu);
+extern int brcmstb_cpu_get_power_state(unsigned int cpu);
+extern struct smp_operations brcmstb_smp_ops;
+#ifdef CONFIG_HOTPLUG_CPU
+extern void brcmstb_cpu_die(unsigned int cpu);
+extern int brcmstb_cpu_kill(unsigned int cpu);
+void __init brcmstb_cpu_ctrl_setup(unsigned int max_cpus);
+#else
+static inline void brcmstb_cpu_die(unsigned int cpu) {}
+static inline int brcmstb_cpu_kill(unsigned int cpu) {}
+static inline void __init brcmstb_cpu_ctrl_setup(unsigned int max_cpus) {}
+#endif
+#endif
+
+enum {
+	GEN_CTRL_V1_RST_SRC_EN = 0,
+	GEN_CTRL_V1_SW_MSTR_RST,
+	GEN_CTRL_V1_CPU_RST_CFG,
+	GEN_CTRL_V1_CPU_PWR_ZONE_CTRL,
+	GEN_CTRL_V1_STB_BOOT_HI_ADDR0,
+};
+
+#endif /* __BRCMSTB_H__ */
diff --git a/arch/arm/mach-bcm/headsmp-brcmstb.S b/arch/arm/mach-bcm/headsmp-brcmstb.S
new file mode 100644
index 0000000..57ec438
--- /dev/null
+++ b/arch/arm/mach-bcm/headsmp-brcmstb.S
@@ -0,0 +1,34 @@
+/*
+ * SMP boot code for secondary CPUs
+ * Based on arch/arm/mach-tegra/headsmp.S
+ *
+ * Copyright (C) 2010 NVIDIA, Inc.
+ * Copyright (C) 2013 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <asm/assembler.h>
+#include <linux/linkage.h>
+#include <linux/init.h>
+
+        .section ".text.head", "ax"
+	__CPUINIT
+
+ENTRY(brcmstb_secondary_startup)
+        /*
+         * Ensure CPU is in a sane state by disabling all IRQs and switching
+         * into SVC mode.
+         */
+        setmode	PSR_I_BIT | PSR_F_BIT | SVC_MODE, r0
+
+        bl      v7_invalidate_l1
+        b       secondary_startup
+ENDPROC(brcmstb_secondary_startup)
diff --git a/arch/arm/mach-bcm/hotplug-brcmstb.c b/arch/arm/mach-bcm/hotplug-brcmstb.c
new file mode 100644
index 0000000..00de2ed
--- /dev/null
+++ b/arch/arm/mach-bcm/hotplug-brcmstb.c
@@ -0,0 +1,252 @@
+/*
+ * Broadcom STB CPU hotplug support for ARM
+ *
+ * Copyright (C) 2013 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/printk.h>
+#include <linux/smp.h>
+
+#include <asm/cacheflush.h>
+#include <asm/mach-types.h>
+
+#include "brcmstb.h"
+
+enum {
+	ZONE_MAN_CLKEN_MASK		= BIT(0),
+	ZONE_MAN_RESET_CNTL_MASK	= BIT(1),
+	ZONE_MAN_MEM_PWR_MASK		= BIT(4),
+	ZONE_RESERVED_1_MASK		= BIT(5),
+	ZONE_MAN_ISO_CNTL_MASK		= BIT(6),
+	ZONE_MANUAL_CONTROL_MASK	= BIT(7),
+	ZONE_PWR_DN_REQ_MASK		= BIT(9),
+	ZONE_PWR_UP_REQ_MASK		= BIT(10),
+	ZONE_BLK_RST_ASSERT_MASK	= BIT(10),
+	ZONE_PWR_OFF_STATE_MASK		= BIT(26),
+	ZONE_PWR_ON_STATE_MASK		= BIT(26),
+	ZONE_DPG_PWR_STATE_MASK		= BIT(28),
+	ZONE_MEM_PWR_STATE_MASK		= BIT(29),
+	ZONE_RESET_STATE_MASK		= BIT(31),
+};
+
+static void __iomem *cpu_rst_cfg_reg;
+static void __iomem *cpu0_pwr_zone_ctrl_reg;
+static void __iomem *hif_cont_reg;
+
+DEFINE_PER_CPU(int, per_cpu_sw_state);
+
+static void __iomem *pwr_ctrl_get_base(unsigned int cpu)
+{
+	void __iomem *base = cpu0_pwr_zone_ctrl_reg;
+	base += (cpu * 4);
+	return base;
+}
+
+static u32 pwr_ctrl_rd(unsigned int cpu)
+{
+	void __iomem *base = pwr_ctrl_get_base(cpu);
+	return readl_relaxed(base);
+}
+
+static void pwr_ctrl_wr(unsigned int cpu, u32 val)
+{
+	void __iomem *base = pwr_ctrl_get_base(cpu);
+	writel(val, base);
+}
+
+void brcmstb_cpu_boot(unsigned int cpu)
+{
+	unsigned long boot_vector;
+	const int reg_ofs = cpu * 8;
+	u32 val;
+
+	pr_info("SMP: Booting CPU%d...\n", cpu);
+
+	/*
+	* set the reset vector to point to the secondary_startup
+	* routine
+	*/
+	boot_vector = virt_to_phys(brcmstb_secondary_startup);
+	writel_relaxed(0, hif_cont_reg + reg_ofs);
+	writel_relaxed(boot_vector, hif_cont_reg + 4 + reg_ofs);
+
+	flush_cache_all();
+
+	/* unhalt the cpu */
+	val = readl_relaxed(cpu_rst_cfg_reg);
+	val &= ~BIT(cpu);
+	writel_relaxed(val, cpu_rst_cfg_reg);
+}
+
+void brcmstb_cpu_power_on(unsigned int cpu)
+{
+	/*
+	 * The secondary cores power was cut, so we must go through
+	 * power-on initialization.
+	 */
+	u32 tmp;
+
+	pr_info("SMP: Powering up CPU%d...\n", cpu);
+
+	/* Request zone power up */
+	pwr_ctrl_wr(cpu, ZONE_PWR_UP_REQ_MASK);
+
+	/* Wait for the power up FSM to complete */
+	do {
+		tmp = pwr_ctrl_rd(cpu);
+	} while (!(tmp & ZONE_PWR_ON_STATE_MASK));
+
+	per_cpu(per_cpu_sw_state, cpu) = 1;
+}
+
+int brcmstb_cpu_get_power_state(unsigned int cpu)
+{
+	int tmp = pwr_ctrl_rd(cpu);
+	return (tmp & ZONE_RESET_STATE_MASK) ? 0 : 1;
+}
+
+void __ref brcmstb_cpu_die(unsigned int cpu)
+{
+	/* Derived from misc_bpcm_arm.c */
+
+	/* Clear SCTLR.C bit */
+	__asm__(
+		"mrc	p15, 0, r0, c1, c0, 0\n"
+		"bic	r0, r0, #(1 << 2)\n"
+		"mcr	p15, 0, r0, c1, c0, 0\n"
+		: /* no output */
+		: /* no input */
+		: "r0"	/* clobber r0 */
+	);
+
+	/*
+	 * Instruction barrier to ensure cache is really disabled before
+	 * cleaning/invalidating the caches
+	 */
+	isb();
+
+	flush_cache_all();
+
+	/* Invalidate all instruction caches to PoU (ICIALLU) */
+	/* Data sync. barrier to ensure caches have emptied out */
+	__asm__("mcr	p15, 0, r0, c7, c5, 0\n" : : : "r0");
+	dsb();
+
+	/*
+	 * Clear ACTLR.SMP bit to prevent broadcast TLB messages from reaching
+	 * this core
+	 */
+	__asm__(
+		"mrc	p15, 0, r0, c1, c0, 1\n"
+		"bic	r0, r0, #(1 << 6)\n"
+		"mcr	p15, 0, r0, c1, c0, 1\n"
+		: /* no output */
+		: /* no input */
+		: "r0"	/* clobber r0 */
+	);
+
+	/* Disable all IRQs for this CPU */
+	arch_local_irq_disable();
+
+	per_cpu(per_cpu_sw_state, cpu) = 0;
+
+	/*
+	 * Final full barrier to ensure everything before this instruction has
+	 * quiesced.
+	 */
+	isb();
+	dsb();
+
+	/* Sit and wait to die */
+	wfi();
+
+	/* We should never get here... */
+	nop();
+	panic("Spurious interrupt on CPU %d received!\n", cpu);
+}
+
+int brcmstb_cpu_kill(unsigned int cpu)
+{
+	u32 tmp;
+	u32 val;
+
+	pr_info("SMP: Powering down CPU%d...\n", cpu);
+
+	while (per_cpu(per_cpu_sw_state, cpu))
+		;
+
+	/* Program zone reset */
+	pwr_ctrl_wr(cpu, ZONE_RESET_STATE_MASK | ZONE_BLK_RST_ASSERT_MASK |
+			      ZONE_PWR_DN_REQ_MASK);
+
+	/* Verify zone reset */
+	tmp = pwr_ctrl_rd(cpu);
+	if (!(tmp & ZONE_RESET_STATE_MASK))
+		pr_err("%s: Zone reset bit for CPU %d not asserted!\n",
+			__func__, cpu);
+
+	/* Wait for power down */
+	do {
+		tmp = pwr_ctrl_rd(cpu);
+	} while (!(tmp & ZONE_PWR_OFF_STATE_MASK));
+
+	/* Settle-time from Broadcom-internal DVT reference code */
+	udelay(7);
+
+	/* Assert reset on the CPU */
+	val = readl_relaxed(cpu_rst_cfg_reg);
+	val |= BIT(cpu);
+	writel_relaxed(val, cpu_rst_cfg_reg);
+
+	return 1;
+}
+
+void __init brcmstb_cpu_ctrl_setup(unsigned int max_cpus)
+{
+	struct device_node *np;
+	char *name;
+
+	name = "brcm,brcmstb-gen-ctrl-v1";
+	np = of_find_compatible_node(NULL, NULL, name);
+	if (!np) {
+		pr_err("can't find compatible node %s\n", name);
+		return;
+	}
+
+	cpu_rst_cfg_reg = of_iomap(np, GEN_CTRL_V1_CPU_RST_CFG);
+	if (!cpu_rst_cfg_reg) {
+		pr_err("iomap failed for cpu_rst_cfg_reg\n");
+		return;
+	}
+
+	cpu0_pwr_zone_ctrl_reg = of_iomap(np, GEN_CTRL_V1_CPU_PWR_ZONE_CTRL);
+	if (!cpu0_pwr_zone_ctrl_reg) {
+		pr_err("iomap failed for cpu0_pwr_zone_ctrl_reg\n");
+		return;
+	}
+
+	hif_cont_reg = of_iomap(np, GEN_CTRL_V1_STB_BOOT_HI_ADDR0);
+	if (!hif_cont_reg) {
+		pr_err("iomap failed for hif_cont_reg\n");
+		return;
+	}
+}
+
-- 
1.7.1

^ permalink raw reply related

* [PATCH v3 0/7] ARM: brcmstb: Add Broadcom STB SoC support
From: Marc Carino @ 2014-01-14 23:48 UTC (permalink / raw)
  To: linux-arm-kernel

This patchset contains the board support package for the
Broadcom BCM7445 ARM-based SoC [1]. These changes contain a
minimal set of code needed for a BCM7445-based board to boot
the Linux kernel.

These changes heavily leverage the OF/devicetree framework.

v3:
- rebased to v3.13-rc8
- switched to using 'multi_v7_defconfig'
- eliminated dependence on compile-time peripheral register access
- moved DT node iomap out from 'init_early'
- misc. minor cleanups from mailing-list discussion for v2

v2:
- rebased to v3.13-rc1
- moved implementation to 'mach-bcm' folder
- added CPU init for B15

v1:
- initial submission

[1] http://www.broadcom.com/products/Cable/Cable-Set-Top-Box-Solutions/BCM7445

Marc Carino (7):
  ARM: brcmstb: add infrastructure for ARM-based Broadcom STB SoCs
  ARM: brcmstb: add debug UART for earlyprintk support
  ARM: do CPU-specific init for Broadcom Brahma15 cores
  ARM: brcmstb: add CPU binding for Broadcom Brahma15
  ARM: brcmstb: add misc. DT bindings for brcm,brcmstb-*
  ARM: brcmstb: gic: add compatible string for Broadcom Brahma15
  ARM: brcmstb: dts: add a reference DTS for Broadcom 7445

 .../devicetree/bindings/arm/brcm-brcmstb.txt       |   43 ++++
 Documentation/devicetree/bindings/arm/cpus.txt     |    1 +
 Documentation/devicetree/bindings/arm/gic.txt      |    1 +
 arch/arm/Kconfig.debug                             |   16 ++-
 arch/arm/boot/dts/brcmstb-7445.dts                 |  104 ++++++++
 arch/arm/configs/multi_v7_defconfig                |    1 +
 arch/arm/mach-bcm/Kconfig                          |   14 +
 arch/arm/mach-bcm/Makefile                         |    4 +
 arch/arm/mach-bcm/brcmstb.c                        |  146 +++++++++++
 arch/arm/mach-bcm/brcmstb.h                        |   46 ++++
 arch/arm/mach-bcm/headsmp-brcmstb.S                |   34 +++
 arch/arm/mach-bcm/hotplug-brcmstb.c                |  252 ++++++++++++++++++++
 arch/arm/mm/proc-v7.S                              |   11 +
 13 files changed, 672 insertions(+), 1 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/brcm-brcmstb.txt
 create mode 100644 arch/arm/boot/dts/brcmstb-7445.dts
 create mode 100644 arch/arm/mach-bcm/brcmstb.c
 create mode 100644 arch/arm/mach-bcm/brcmstb.h
 create mode 100644 arch/arm/mach-bcm/headsmp-brcmstb.S
 create mode 100644 arch/arm/mach-bcm/hotplug-brcmstb.c

^ permalink raw reply

* [PATCH net-next 2/2] net: mvneta: make mvneta_txq_done() return void
From: Arnaud Ebalard @ 2014-01-14 23:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <cover.1389742334.git.arno@natisbad.org>


The function return parameter is not used in mvneta_tx_done_gbe(),
where the function is called. This patch makes the function return
void.

Signed-off-by: Arnaud Ebalard <arno@natisbad.org>
---
 drivers/net/ethernet/marvell/mvneta.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index 8c5150124b5e..f418f4f20f94 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -1314,15 +1314,16 @@ static void mvneta_txq_bufs_free(struct mvneta_port *pp,
 }
 
 /* Handle end of transmission */
-static int mvneta_txq_done(struct mvneta_port *pp,
+static void mvneta_txq_done(struct mvneta_port *pp,
 			   struct mvneta_tx_queue *txq)
 {
 	struct netdev_queue *nq = netdev_get_tx_queue(pp->dev, txq->id);
 	int tx_done;
 
 	tx_done = mvneta_txq_sent_desc_proc(pp, txq);
-	if (tx_done == 0)
-		return tx_done;
+	if (!tx_done)
+		return;
+
 	mvneta_txq_bufs_free(pp, txq, tx_done);
 
 	txq->count -= tx_done;
@@ -1331,8 +1332,6 @@ static int mvneta_txq_done(struct mvneta_port *pp,
 		if (txq->size - txq->count >= MAX_SKB_FRAGS + 1)
 			netif_tx_wake_queue(nq);
 	}
-
-	return tx_done;
 }
 
 static void *mvneta_frag_alloc(const struct mvneta_port *pp)
-- 
1.8.5.2

^ permalink raw reply related

* [GIT PULL] at91: cleanup for 3.14 #2
From: Kevin Hilman @ 2014-01-14 23:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1389190989-8261-1-git-send-email-nicolas.ferre@atmel.com>

Nicolas Ferre <nicolas.ferre@atmel.com> writes:

> Arnd, Olof, Kevin,
>
> A little "cleanup" pull-request for 3.14 that goes on top of the previous
> AT91 cleanup material.
> The thing to note from this pull-request is the beginning of board file removal
> thank to the conversion to DT. We are still waiting for more feedback from
> board maintainer to intensify the effort.
>
> Thanks, best regards,
>
> The following changes since commit b46e837d8ef1f3c777bbf9513e2cdb5d87d6c374:
>
>   ARM: at91/dt: remove old clk material (2013-12-02 15:31:29 +0100)
>
> are available in the git repository at:
>
>   git://github.com/at91linux/linux-at91.git tags/at91-cleanup2
>
> for you to fetch changes up to e91a5555df5883bbc204b0e1f8e0489d3f7f3f2e:
>
>   ARM: at91: switch Calao QIL-A9260 board to DT (2013-12-19 17:27:30 +0100)
>
> ----------------------------------------------------------------
> Second cleanup pull-request for 3.14:
> - a tiny fix for the recent AT91 CCF implementation
> - the switch of one platform to DT with board file removal
>
> ----------------------------------------------------------------

Pulled into next/cleanup.

Thanks,

Kevin

^ permalink raw reply

* [PATCH net-next 1/2] net: mvneta: mvneta_tx_done_gbe() cleanups
From: Arnaud Ebalard @ 2014-01-14 23:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <cover.1389742334.git.arno@natisbad.org>


mvneta_tx_done_gbe() return value and third parameter are no more
used. This patch changes the function prototype and removes a useless
variable where the function is called.

Signed-off-by: Arnaud Ebalard <arno@natisbad.org>
---
 drivers/net/ethernet/marvell/mvneta.c | 17 ++++-------------
 1 file changed, 4 insertions(+), 13 deletions(-)

diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index f5fc7a249880..8c5150124b5e 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -1704,30 +1704,23 @@ static void mvneta_txq_done_force(struct mvneta_port *pp,
 /* Handle tx done - called in softirq context. The <cause_tx_done> argument
  * must be a valid cause according to MVNETA_TXQ_INTR_MASK_ALL.
  */
-static u32 mvneta_tx_done_gbe(struct mvneta_port *pp, u32 cause_tx_done,
-			      int *tx_todo)
+static void mvneta_tx_done_gbe(struct mvneta_port *pp, u32 cause_tx_done)
 {
 	struct mvneta_tx_queue *txq;
-	u32 tx_done = 0;
 	struct netdev_queue *nq;
 
-	*tx_todo = 0;
 	while (cause_tx_done) {
 		txq = mvneta_tx_done_policy(pp, cause_tx_done);
 
 		nq = netdev_get_tx_queue(pp->dev, txq->id);
 		__netif_tx_lock(nq, smp_processor_id());
 
-		if (txq->count) {
-			tx_done += mvneta_txq_done(pp, txq);
-			*tx_todo += txq->count;
-		}
+		if (txq->count)
+			mvneta_txq_done(pp, txq);
 
 		__netif_tx_unlock(nq);
 		cause_tx_done &= ~((1 << txq->id));
 	}
-
-	return tx_done;
 }
 
 /* Compute crc8 of the specified address, using a unique algorithm ,
@@ -1961,9 +1954,7 @@ static int mvneta_poll(struct napi_struct *napi, int budget)
 
 	/* Release Tx descriptors */
 	if (cause_rx_tx & MVNETA_TX_INTR_MASK_ALL) {
-		int tx_todo = 0;
-
-		mvneta_tx_done_gbe(pp, (cause_rx_tx & MVNETA_TX_INTR_MASK_ALL), &tx_todo);
+		mvneta_tx_done_gbe(pp, (cause_rx_tx & MVNETA_TX_INTR_MASK_ALL));
 		cause_rx_tx &= ~MVNETA_TX_INTR_MASK_ALL;
 	}
 
-- 
1.8.5.2

^ permalink raw reply related

* [PATCH net-next 0/2] net: mvneta: simple cleanups
From: Arnaud Ebalard @ 2014-01-14 23:45 UTC (permalink / raw)
  To: linux-arm-kernel


Those two patches are intended for net-next. They apply on top of
performance improvements patches from Willy for mvneta driver.
They provide some simple cleanups for unused variables, function
params or return values.

Arnaud Ebalard (2):
  net: mvneta: mvneta_tx_done_gbe() cleanups
  net: mvneta: make mvneta_txq_done() return void

 drivers/net/ethernet/marvell/mvneta.c | 26 ++++++++------------------
 1 file changed, 8 insertions(+), 18 deletions(-)

-- 
1.8.5.2

^ permalink raw reply

* [PATCH] ARM: OMAP4: sleep: byteswap data for big-endian
From: Santosh Shilimkar @ 2014-01-14 23:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAGo_u6oGDK5s0SeE6Z7UFM6eYdgoy-E+Tj67+pBWP-wQ3r9=QA@mail.gmail.com>

On Tuesday 14 January 2014 04:13 PM, Nishanth Menon wrote:
> On Tue, Jan 14, 2014 at 3:03 PM, Santosh Shilimkar
> <santosh.shilimkar@ti.com> wrote:
>>
>>> ok.. some sort of Linaro thing about which I have no background about
>>> - but dont really care in this context.
>>>
>> Nothing related Linaro. Its just that platforms are supporting ARM BE
>> mode and Linaro folks had working patches for Panda. So I suggested
>> to get them on the lists.
> 
> I tend to think -> is this with OFF mode and CPUidle completely
> working? All context save and restore works with this? on HS and GP
> devices with BE mode builds? works on SDP4430,60 variations,
> considered reuse with AM43xx which could use parts of that logic?
> 
> I mean to indicate that terms like "works on panda" tends always to be relative.
>
Fair enough.
 
> It is nice to see it as a proof of concept, but I'd hate to see some
> dead code lying around in kernel and folks blindly following suit and
> introducing macros for new assembly for a feature that in practice
> just one group of folks care about and creates additional burden for
> rest of folks trying to keep that functionality going as we jump from
> one "device tree" style churn to another "framework"? Not to mean that
> good features should be kept away.. but personally, I could not find
> convincing arguments in this case..
> 
I haven't looked at patch myself but as you pointed out if it adds
dead code and makes the code un-readable then probably that something
we shouldn't merge.

Regards,
Santosh

^ permalink raw reply

* [PATCH v4 4/6] spmi: pmic_arb: add support for interrupt handling
From: Courtney Cavin @ 2014-01-14 23:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <0f3e257f098d5f1ec6e9f09ba4dbf055291f2d83.1389738151.git.joshc@codeaurora.org>

On Tue, Jan 14, 2014 at 07:41:38PM +0100, Josh Cartwright wrote:
> The Qualcomm PMIC Arbiter, in addition to being a basic SPMI controller,
> also implements interrupt handling for slave devices.  Note, this is
> outside the scope of SPMI, as SPMI leaves interrupt handling completely
> unspecified.
> 
> Extend the driver to provide a irq_chip implementation and chained irq
> handling which allows for these interrupts to be used.
> 
> Signed-off-by: Josh Cartwright <joshc@codeaurora.org>
> ---
>  drivers/spmi/spmi-pmic-arb.c | 393 ++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 391 insertions(+), 2 deletions(-)
> 

Yay! Good to see this series.

> diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
> index 16083cd..32bed54 100644
> --- a/drivers/spmi/spmi-pmic-arb.c
> +++ b/drivers/spmi/spmi-pmic-arb.c
> @@ -13,6 +13,9 @@
>  #include <linux/err.h>
>  #include <linux/interrupt.h>
>  #include <linux/io.h>
> +#include <linux/irqchip/chained_irq.h>
> +#include <linux/irqdomain.h>
> +#include <linux/irq.h>
>  #include <linux/kernel.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
> @@ -103,6 +106,14 @@ enum pmic_arb_cmd_op_code {
>   * @cnfg:              address of the PMIC Arbiter configuration registers.
>   * @lock:              lock to synchronize accesses.
>   * @channel:           which channel to use for accesses.
> + * @irq:               PMIC ARB interrupt.
> + * @ee:                        the current Execution Environment
> + * @min_apid:          minimum APID (used for bounding IRQ search)
> + * @max_apid:          maximum APID
> + * @mapping_table:     in-memory copy of PPID -> APID mapping table.
> + * @domain:            irq domain object for PMIC IRQ domain
> + * @spmic:             SPMI controller object
> + * @apid_to_ppid:      cached mapping from APID to PPID
>   */
>  struct spmi_pmic_arb_dev {
>         void __iomem            *base;
> @@ -110,6 +121,14 @@ struct spmi_pmic_arb_dev {
>         void __iomem            *cnfg;
>         spinlock_t              lock;
>         u8                      channel;
> +       unsigned int            irq;
> +       u8                      ee;
> +       u8                      min_apid;
> +       u8                      max_apid;
> +       u32                     mapping_table[SPMI_MAPPING_TABLE_LEN];
> +       struct irq_domain       *domain;
> +       struct spmi_controller  *spmic;
> +       u16                     apid_to_ppid[256];
>  };
> 
>  static inline u32 pmic_arb_base_read(struct spmi_pmic_arb_dev *dev, u32 offset)
> @@ -314,12 +333,333 @@ static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
>         return rc;
>  }
> 
> +enum qpnpint_regs {
> +       QPNPINT_REG_RT_STS              = 0x10,
> +       QPNPINT_REG_SET_TYPE            = 0x11,
> +       QPNPINT_REG_POLARITY_HIGH       = 0x12,
> +       QPNPINT_REG_POLARITY_LOW        = 0x13,
> +       QPNPINT_REG_LATCHED_CLR         = 0x14,
> +       QPNPINT_REG_EN_SET              = 0x15,
> +       QPNPINT_REG_EN_CLR              = 0x16,
> +       QPNPINT_REG_LATCHED_STS         = 0x18,
> +};
> +
> +struct spmi_pmic_arb_qpnpint_type {
> +       u8 type; /* 1 -> edge */
> +       u8 polarity_high;
> +       u8 polarity_low;
> +} __packed;
> +

While the rest of this driver uses 'pmic' or 'spmi_pmic', this patch
adds 'qpnpint'.  Can we please just leave the software fabricated name
'qpnp' out of any changes, as it isn't in any hardware spec?  Perhaps
'pmic_int' or something along those lines?

> +/* Simplified accessor functions for irqchip callbacks */
> +static void qpnpint_spmi_write(struct irq_data *d, u8 reg, void *buf,
> +                              size_t len)
[...]

-Courtney

^ permalink raw reply

* [Intel-gfx] [PATCH 1/2] drm: share drm_add_fake_info_node
From: Russell King - ARM Linux @ 2014-01-14 23:40 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140114232510.GV4770@phenom.ffwll.local>

On Wed, Jan 15, 2014 at 12:25:10AM +0100, Daniel Vetter wrote:
> On Tue, Jan 14, 2014 at 06:14:06AM -0800, Ben Widawsky wrote:
> > Both i915 and Armada had the exact same implementation. For an upcoming
> > patch, I'd like to call this function from two different source files in
> > i915, and having it available externally helps there too.
> > 
> > While moving, add 'debugfs_' to the name in order to match the other drm
> > debugfs helper functions.
> > 
> > Cc: linux-arm-kernel at lists.infradead.org
> > Cc: intel-gfx at lists.freedesktop.org
> > Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
> 
> drm_debugfs_create_files in drm_debugfs.c has the almost same code again.
> Now the problem here is that the interface is a bit botched up, since all
> the users in i915 and armada actaully faile to clean up teh debugfs dentry
> if drm_add_fake_info_node.

That's not correct - armada does clean up these, I think you need to
take a closer look at the code.

We do this by setting node->info_ent to the file operations structure,
which is a unique key to the file being registered.

Upon failure to create the fake node, we appropriately call
drm_debugfs_remove_files() with the first argument being a pointer to
the file operations.  This causes drm_debugfs_remove_files() to match
the fake entry, call debugfs_remove() on the dentry, and remove the
node from the list, and free the node structure we allocated.

Upon driver teardown, we also call drm_debugfs_remove_files() but with
each fops which should be registered, thus cleaning up each fake node
which was created.

So, Armada does clean up these entries properly.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

^ permalink raw reply

* [GIT PULL] minor Versatile updates
From: Kevin Hilman @ 2014-01-14 23:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CACRpkdZFDCScea24A=CnV+Yxv-nZGxFKfhQsbvMHbxywwatPsA@mail.gmail.com>

Linus Walleij <linus.walleij@linaro.org> writes:

> Hi ARM SoC folks,
>
> the following is just one minor cleanup and then defconfig changes to
> set the scene for future Versatile cleanup/multiplatform work.
>
> Please pull it in to ARM SoC, the defconfig changes are even post-rc1
> material in some sense.
>
> Yours,
> Linus Walleij
>
>
> The following changes since commit 319e2e3f63c348a9b66db4667efa73178e18b17d:
>
>   Linux 3.13-rc4 (2013-12-15 12:31:33 -0800)
>
> are available in the git repository at:
>
>   git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-integrator.git
> tags/versatile-for-v3.14
>
> for you to fetch changes up to 27d2adb5969eef7ff3bfeb2dc3b2064e3a124952:
>
>   ARM: versatile: enable LEDs by default (2013-12-20 18:22:49 +0100)
>
> ----------------------------------------------------------------
> Versatile patches for v3.14:
>
> - Move GPIO2 and GPIO3 to be registered from the core boardfile.
>
> - Update the defconfig.
>
> Defconfig changes:
>
> - Enable GPIOLIB and PL061 for the Versatile.
>
> - Build the Versatile using EABI.
>
> - Enable the new LEDs in the defconfig.
>
> ----------------------------------------------------------------

Pulled into next/soc.

Thanks,

Kevin

^ permalink raw reply

* [RFC PATCH V2 4/4] MAINTAINERS: entry for APM X-Gene PCIe host driver
From: Tanmay Inamdar @ 2014-01-14 23:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1389742458-7693-1-git-send-email-tinamdar@apm.com>

Add entry for AppliedMicro X-Gene PCIe host driver.

Signed-off-by: Tanmay Inamdar <tinamdar@apm.com>
---
 MAINTAINERS |    7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 6c20792..9e3ed53 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6531,6 +6531,13 @@ L:	linux-pci at vger.kernel.org
 S:	Maintained
 F:	drivers/pci/host/*designware*
 
+PCI DRIVER FOR APPLIEDMICRO XGENE
+M:	Tanmay Inamdar <tinamdar@apm.com>
+L:	linux-pci at vger.kernel.org
+L:	linux-arm-kernel at lists.infradead.org
+S:	Maintained
+F:	drivers/pci/host/pci-xgene.c
+
 PCMCIA SUBSYSTEM
 P:	Linux PCMCIA Team
 L:	linux-pcmcia at lists.infradead.org
-- 
1.7.9.5

^ permalink raw reply related

* [RFC PATCH V2 3/4] dt-bindings: pci: xgene pcie device tree bindings
From: Tanmay Inamdar @ 2014-01-14 23:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1389742458-7693-1-git-send-email-tinamdar@apm.com>

This patch adds the bindings for X-Gene PCIe driver. The driver resides
under 'drivers/pci/host/pci-xgene.c' file.

Signed-off-by: Tanmay Inamdar <tinamdar@apm.com>
---
 .../devicetree/bindings/pci/xgene-pcie.txt         |   45 ++++++++++++++++++++
 1 file changed, 45 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pci/xgene-pcie.txt

diff --git a/Documentation/devicetree/bindings/pci/xgene-pcie.txt b/Documentation/devicetree/bindings/pci/xgene-pcie.txt
new file mode 100644
index 0000000..19b9c28
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/xgene-pcie.txt
@@ -0,0 +1,45 @@
+* AppliedMicro X-Gene PCIe interface
+
+Required properties:
+- status: Either "ok" or "disabled".
+- device_type: set to "pci"
+- compatible: should contain "xgene,pcie" to identify the core.
+- reg: base addresses and lengths of the pcie controller configuration
+	space register.
+- #address-cells: set to <3>
+- #size-cells: set to <2>
+- ranges: ranges for the outbound memory, I/O regions.
+- dma-ranges: ranges for the inbound memory regions.
+- #interrupt-cells: set to <1>
+- interrupt-map-mask and interrupt-map: standard PCI properties
+	to define the mapping of the PCIe interface to interrupt
+	numbers.
+- clocks: from common clock binding: handle to pci clock.
+
+Example:
+
+SoC specific DT Entry:
+	pcie0: pcie at 1f2b0000 {
+		status = "disabled";
+		device_type = "pci";
+		compatible = "apm,xgene-pcie";
+		#interrupt-cells = <1>;
+		#size-cells = <2>;
+		#address-cells = <3>;
+		reg = < 0x00 0x1f2b0000 0x0 0x00010000
+			0xe0 0xd0000000 0x0 0x00200000>;
+		ranges = <0x01000000 0x00 0x00000000 0xe0 0x00000000 0x00 0x00010000   /* io */
+			  0x02000000 0x00 0x10000000 0xe0 0x10000000 0x00 0x80000000>; /* mem */
+		dma-ranges = <0x42000000 0x40 0x00000000 0x40 0x00000000 0x40 0x00000000>;
+		interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+		interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xc2 0x1
+				 0x0 0x0 0x0 0x2 &gic 0x0 0xc3 0x1
+				 0x0 0x0 0x0 0x3 &gic 0x0 0xc4 0x1
+				 0x0 0x0 0x0 0x4 &gic 0x0 0xc5 0x1>;
+		clocks = <&pcie0clk 0>;
+	};
+
+Board specific DT Entry:
+	&pcie0 {
+		status = "ok";
+	};
-- 
1.7.9.5

^ permalink raw reply related

* [RFC PATCH V2 2/4] arm64:dts: APM X-Gene PCIe device tree nodes
From: Tanmay Inamdar @ 2014-01-14 23:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1389742458-7693-1-git-send-email-tinamdar@apm.com>

This patch adds the device tree nodes for APM X-Gene PCIe controller and
PCIe clock interface. Since X-Gene SOC supports maximum 5 ports, 5 dts
nodes are added.

Signed-off-by: Tanmay Inamdar <tinamdar@apm.com>
---
 arch/arm64/boot/dts/apm-mustang.dts |    4 +
 arch/arm64/boot/dts/apm-storm.dtsi  |  144 +++++++++++++++++++++++++++++++++++
 2 files changed, 148 insertions(+)

diff --git a/arch/arm64/boot/dts/apm-mustang.dts b/arch/arm64/boot/dts/apm-mustang.dts
index 1247ca1..ab2b95f 100644
--- a/arch/arm64/boot/dts/apm-mustang.dts
+++ b/arch/arm64/boot/dts/apm-mustang.dts
@@ -24,3 +24,7 @@
 		reg = < 0x1 0x00000000 0x0 0x80000000 >; /* Updated by bootloader */
 	};
 };
+
+&pcie0 {
+	status = "ok";
+};
diff --git a/arch/arm64/boot/dts/apm-storm.dtsi b/arch/arm64/boot/dts/apm-storm.dtsi
index d37d736..6b8b995 100644
--- a/arch/arm64/boot/dts/apm-storm.dtsi
+++ b/arch/arm64/boot/dts/apm-storm.dtsi
@@ -176,6 +176,150 @@
 				reg-names = "csr-reg";
 				clock-output-names = "eth8clk";
 			};
+
+			pcie0clk: pcie0clk at 1f2bc000 {
+				compatible = "apm,xgene-device-clock";
+				#clock-cells = <1>;
+				clocks = <&socplldiv2 0>;
+				reg = <0x0 0x1f2bc000 0x0 0x1000>;
+				reg-names = "csr-reg";
+				clock-output-names = "pcie0clk";
+			};
+
+			pcie1clk: pcie1clk at 1f2cc000 {
+				compatible = "apm,xgene-device-clock";
+				#clock-cells = <1>;
+				clocks = <&socplldiv2 0>;
+				reg = <0x0 0x1f2cc000 0x0 0x1000>;
+				reg-names = "csr-reg";
+				clock-output-names = "pcie1clk";
+			};
+
+			pcie2clk: pcie2clk at 1f2dc000 {
+				compatible = "apm,xgene-device-clock";
+				#clock-cells = <1>;
+				clocks = <&socplldiv2 0>;
+				reg = <0x0 0x1f2dc000 0x0 0x1000>;
+				reg-names = "csr-reg";
+				clock-output-names = "pcie2clk";
+			};
+
+			pcie3clk: pcie3clk at 1f50c000 {
+				compatible = "apm,xgene-device-clock";
+				#clock-cells = <1>;
+				clocks = <&socplldiv2 0>;
+				reg = <0x0 0x1f50c000 0x0 0x1000>;
+				reg-names = "csr-reg";
+				clock-output-names = "pcie3clk";
+			};
+
+			pcie4clk: pcie4clk at 1f51c000 {
+				compatible = "apm,xgene-device-clock";
+				#clock-cells = <1>;
+				clocks = <&socplldiv2 0>;
+				reg = <0x0 0x1f51c000 0x0 0x1000>;
+				reg-names = "csr-reg";
+				clock-output-names = "pcie4clk";
+			};
+		};
+
+		pcie0: pcie at 1f2b0000 {
+			status = "disabled";
+			device_type = "pci";
+			compatible = "apm,xgene-pcie";
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			reg = < 0x00 0x1f2b0000 0x0 0x00010000
+				0xe0 0xd0000000 0x0 0x00200000>;
+			ranges = <0x01000000 0x00 0x00000000 0xe0 0x00000000 0x00 0x00010000   /* io */
+				  0x02000000 0x00 0x10000000 0xe0 0x10000000 0x00 0x80000000>; /* mem */
+			dma-ranges = <0x42000000 0x40 0x00000000 0x40 0x00000000 0x40 0x00000000>;
+			interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+			interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xc2 0x1
+					 0x0 0x0 0x0 0x2 &gic 0x0 0xc3 0x1
+					 0x0 0x0 0x0 0x3 &gic 0x0 0xc4 0x1
+					 0x0 0x0 0x0 0x4 &gic 0x0 0xc5 0x1>;
+			clocks = <&pcie0clk 0>;
+		};
+
+		pcie1: pcie at 1f2c0000 {
+			status = "disabled";
+			device_type = "pci";
+			compatible = "apm,xgene-pcie";
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			reg = < 0x00 0x1f2c0000 0x0 0x00010000
+				0xd0 0xd0000000 0x0 0x00200000>;
+			ranges = <0x01000000 0x0 0x00000000 0xd0 0x00000000 0x00 0x00010000   /* io  */
+				  0x02000000 0x0 0x10000000 0xd0 0x10000000 0x00 0x80000000>; /* mem */
+			dma-ranges = <0x42000000 0x40 0x00000000 0x40 0x00000000 0x40 0x00000000>;
+			interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+			interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xc8 0x1
+					 0x0 0x0 0x0 0x2 &gic 0x0 0xc9 0x1
+					 0x0 0x0 0x0 0x3 &gic 0x0 0xca 0x1
+					 0x0 0x0 0x0 0x4 &gic 0x0 0xcb 0x1>;
+			clocks = <&pcie1clk 0>;
+		};
+
+		pcie2: pcie at 1f2d0000 {
+			status = "disabled";
+			device_type = "pci";
+			compatible = "apm,xgene-pcie";
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			reg =  < 0x00 0x1f2d0000 0x0 0x00010000
+				 0x90 0xd0000000 0x0 0x00200000>;
+			ranges = <0x01000000 0x0 0x00000000 0x90 0x00000000 0x0 0x00010000   /* io  */
+				  0x02000000 0x0 0x10000000 0x90 0x10000000 0x0 0x80000000>; /* mem */
+			dma-ranges = <0x42000000 0x40 0x00000000 0x40 0x00000000 0x40 0x00000000>;
+			interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+			interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xce 0x1
+					 0x0 0x0 0x0 0x2 &gic 0x0 0xcf 0x1
+					 0x0 0x0 0x0 0x3 &gic 0x0 0xd0 0x1
+					 0x0 0x0 0x0 0x4 &gic 0x0 0xd1 0x1>;
+			clocks = <&pcie2clk 0>;
+		};
+
+		pcie3: pcie at 1f500000 {
+			status = "disabled";
+			device_type = "pci";
+			compatible = "apm,xgene-pcie";
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			reg = < 0x00 0x1f500000 0x0 0x00010000
+				0xa0 0xd0000000 0x0 0x00200000>;
+			ranges = <0x01000000 0x0 0x00000000 0xa0 0x00000000 0x0 0x00010000  /* mem */
+				  0x02000000 0x0 0x10000000 0xa0 0x10000000 0x0 0x80000000>; /* io  */
+			dma-ranges = <0x42000000 0x40 0x00000000 0x40 0x00000000 0x40 0x00000000>;
+			interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+			interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xd4 0x1
+					 0x0 0x0 0x0 0x2 &gic 0x0 0xd5 0x1
+					 0x0 0x0 0x0 0x3 &gic 0x0 0xd6 0x1
+					 0x0 0x0 0x0 0x4 &gic 0x0 0xd7 0x1>;
+			clocks = <&pcie3clk 0>;
+		};
+
+		pcie4: pcie at 1f510000 {
+			status = "disabled";
+			device_type = "pci";
+			compatible = "apm,xgene-pcie";
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			reg = <0x00 0x1f510000 0x0 0x00010000>;
+			ranges = <0x01000000 0x0 0x00000000 0xc0 0x00000000 0x0 0x00010000   /* io  */
+				  0x02000000 0x0 0x10000000 0xc0 0x10000000 0x0 0x80000000>; /* mem */
+			dma-ranges = <0x42000000 0x40 0x00000000 0x40 0x00000000 0x40 0x00000000>;
+			interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+			interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xda 0x1
+					 0x0 0x0 0x0 0x2 &gic 0x0 0xdb 0x1
+					 0x0 0x0 0x0 0x3 &gic 0x0 0xdc 0x1
+					 0x0 0x0 0x0 0x4 &gic 0x0 0xdd 0x1>;
+			clocks = <&pcie4clk 0>;
 		};
 
 		serial0: serial at 1c020000 {
-- 
1.7.9.5

^ permalink raw reply related

* [RFC PATCH V2 1/4] pci: APM X-Gene PCIe controller driver
From: Tanmay Inamdar @ 2014-01-14 23:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1389742458-7693-1-git-send-email-tinamdar@apm.com>

This patch adds the AppliedMicro X-Gene SOC PCIe controller driver.
X-Gene PCIe controller supports maxmum upto 8 lanes and GEN3 speed.
X-Gene has maximum 5 PCIe ports supported.

Signed-off-by: Tanmay Inamdar <tinamdar@apm.com>
---
 drivers/pci/host/Kconfig     |   10 +
 drivers/pci/host/Makefile    |    1 +
 drivers/pci/host/pci-xgene.c |  934 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 945 insertions(+)
 create mode 100644 drivers/pci/host/pci-xgene.c

diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index 47d46c6..19ce97d 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -33,4 +33,14 @@ config PCI_RCAR_GEN2
 	  There are 3 internal PCI controllers available with a single
 	  built-in EHCI/OHCI host controller present on each one.
 
+config PCI_XGENE
+	bool "X-Gene PCIe controller"
+	depends on ARCH_XGENE
+	depends on OF
+	select PCIEPORTBUS
+	help
+	  Say Y here if you want internal PCI support on APM X-Gene SoC.
+	  There are 5 internal PCIe ports available. Each port is GEN3 capable
+	  and have varied lanes from x1 to x8.
+
 endmenu
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index 13fb333..34c7c36 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -4,3 +4,4 @@ obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
 obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
 obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
 obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
+obj-$(CONFIG_PCI_XGENE) += pci-xgene.o
diff --git a/drivers/pci/host/pci-xgene.c b/drivers/pci/host/pci-xgene.c
new file mode 100644
index 0000000..54b2d4f
--- /dev/null
+++ b/drivers/pci/host/pci-xgene.c
@@ -0,0 +1,934 @@
+/**
+ * APM X-Gene PCIe Driver
+ *
+ * Copyright (c) 2013 Applied Micro Circuits Corporation.
+ *
+ * Author: Tanmay Inamdar <tinamdar@apm.com>.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * 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.
+ *
+ */
+#include <linux/clk-private.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/memblock.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_pci.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <asm/pcibios.h>
+
+#define PCIECORE_LTSSM			0x4c
+#define PCIECORE_CTLANDSTATUS		0x50
+#define PIPE_PHY_RATE_RD(src)		((0xc000 & (u32)(src)) >> 0xe)
+#define INTXSTATUSMASK			0x6c
+#define PIM1_1L				0x80
+#define IBAR2				0x98
+#define IR2MSK				0x9c
+#define PIM2_1L				0xa0
+#define IBAR3L				0xb4
+#define IR3MSKL				0xbc
+#define PIM3_1L				0xc4
+#define OMR1BARL			0x100
+#define OMR2BARL			0x118
+#define CFGBARL				0x154
+#define CFGBARH				0x158
+#define CFGCTL				0x15c
+#define RTDID				0x160
+#define BRIDGE_CFG_0			0x2000
+#define BRIDGE_CFG_1			0x2004
+#define BRIDGE_CFG_4			0x2010
+#define BRIDGE_CFG_32			0x2030
+#define BRIDGE_CFG_14			0x2038
+#define BRIDGE_8G_CFG_0			0x2100
+#define BRIDGE_8G_CFG_4			0x2110
+#define BRIDGE_8G_CFG_8			0x2120
+#define BRIDGE_8G_CFG_9			0x2124
+#define BRIDGE_8G_CFG_10		0x2128
+#define BRIDGE_8G_CFG_11		0x212c
+#define BRIDGE_CTRL_1			0x2204
+#define BRIDGE_CTRL_2			0x2208
+#define BRIDGE_CTRL_5			0x2214
+#define BRIDGE_STATUS_0			0x2600
+#define MEM_RAM_SHUTDOWN                0xd070
+#define BLOCK_MEM_RDY                   0xd074
+
+#define PCI_PRIMARY_BUS_MASK		0x00ffffff
+#define REVISION_ID_MASK		0x000000ff
+#define SLOT_IMPLEMENTED_MASK		0x04000000
+#define DEVICE_PORT_TYPE_MASK		0x03c00000
+#define ADVT_INFINITE_CREDITS		0x00000200
+#define PM_FORCE_RP_MODE_MASK		0x00000400
+#define SWITCH_PORT_MODE_MASK		0x00000800
+#define CLASS_CODE_MASK			0xffffff00
+#define LINK_UP_MASK			0x00000100
+#define AER_OPTIONAL_ERROR_EN		0xffc00000
+#define DWNSTRM_EQ_SKP_PHS_2_3		0x00010000
+#define DIRECT_TO_5GTS_MASK		0x00020000
+#define SUPPORT_5GTS_MASK		0x00010000
+#define DIRECT_TO_8GTS_MASK		0x00008000
+#define SUPPORT_8GTS_MASK		0x00004000
+#define XGENE_PCIE_DEV_CTRL		0x2f0f
+#define AXI_EP_CFG_ACCESS		0x10000
+#define ENABLE_ASPM			0x08000000
+#define XGENE_PORT_TYPE_RC		0x05000000
+#define BLOCK_MEM_RDY_VAL               0xFFFFFFFF
+#define EN_COHERENCY			0xF0000000
+#define EN_REG				0x00000001
+#define OB_LO_IO			0x00000002
+#define XGENE_PCIE_VENDORID		0xE008
+#define XGENE_PCIE_DEVICEID		0xE004
+#define XGENE_PCIE_TIMEOUT		(500*1000) /* us */
+#define XGENE_LTSSM_DETECT_WAIT		20
+#define XGENE_LTSSM_L0_WAIT		4
+#define XGENE_PCIE_MAX_PORTS		5
+#define SZ_1T				(SZ_1G*1024ULL)
+
+struct xgene_res_cfg {
+	struct resource		res;
+	u64			pci_addr;
+};
+
+struct xgene_pcie_port {
+	struct device_node		*node;
+	struct xgene_res_cfg		mem;
+	struct xgene_res_cfg		io;
+	u8				link_up;
+	u8				link_speed;
+	u32				first_busno;
+	void				*csr_base;
+	void				*cfg_base;
+	u64				cfg_addr;
+	struct device			*dev;
+	struct clk			*clk;
+};
+
+static inline u32 pcie_bar_low_val(u32 addr, u32 flags)
+{
+	return (addr & PCI_BASE_ADDRESS_MEM_MASK) | flags;
+}
+
+static inline u32 eq_pre_cursor_lane0_set(u32 dst, u32 src)
+{
+	return (dst & ~0xff) | (src & 0xff);
+}
+
+static inline u32 eq_pre_cursor_lane1_set(u32 dst, u32 src)
+{
+	return (dst & ~0xff0000) | ((src << 0x10) & 0xff0000);
+}
+
+static inline struct xgene_pcie_port *
+xgene_pcie_sys_to_port(struct pci_sys_data *sys)
+{
+	return sys->private_data;
+}
+
+static inline struct xgene_pcie_port *
+xgene_pcie_bus_to_port(struct pci_bus *bus)
+{
+	struct pci_sys_data *sys = bus->sysdata;
+	return xgene_pcie_sys_to_port(sys);
+}
+
+/* PCIE Configuration Out/In */
+static inline void xgene_pcie_cfg_out32(void *addr, u32 val)
+{
+	writel(val, addr);
+}
+
+static inline void xgene_pcie_cfg_out16(void *addr, u16 val)
+{
+	u64 temp_addr = (u64) addr & ~0x3;
+	u32 val32 = readl((void *)temp_addr);
+
+	switch ((u64) addr & 0x3) {
+	case 2:
+		val32 &= ~0xFFFF0000;
+		val32 |= (u32) val << 16;
+		break;
+	case 0:
+	default:
+		val32 &= ~0xFFFF;
+		val32 |= val;
+		break;
+	}
+	writel(val32, (void *)temp_addr);
+}
+
+static inline void xgene_pcie_cfg_out8(void *addr, u8 val)
+{
+	phys_addr_t temp_addr = (u64) addr & ~0x3;
+	u32 val32 = readl((void *)temp_addr);
+
+	switch ((u64) addr & 0x3) {
+	case 0:
+		val32 &= ~0xFF;
+		val32 |= val;
+		break;
+	case 1:
+		val32 &= ~0xFF00;
+		val32 |= (u32) val << 8;
+		break;
+	case 2:
+		val32 &= ~0xFF0000;
+		val32 |= (u32) val << 16;
+		break;
+	case 3:
+	default:
+		val32 &= ~0xFF000000;
+		val32 |= (u32) val << 24;
+		break;
+	}
+	writel(val32, (void *)temp_addr);
+}
+
+static inline void xgene_pcie_cfg_in32(void *addr, u32 *val)
+{
+	*val = readl(addr);
+}
+
+static inline void xgene_pcie_cfg_in16(void *addr, u16 *val)
+{
+	u64 temp_addr = (u64)addr & ~0x3;
+	u32 val32;
+
+	val32 = readl((void *)temp_addr);
+
+	switch ((u64)addr & 0x3) {
+	case 2:
+		*val = val32 >> 16;
+		break;
+	case 0:
+	default:
+		*val = val32;
+		break;
+	}
+}
+
+static inline void xgene_pcie_cfg_in8(void *addr, u8 *val)
+{
+	u64 temp_addr = (u64)addr & ~0x3;
+	u32 val32;
+
+	val32 = readl((void *)temp_addr);
+
+	switch ((u64)addr & 0x3) {
+	case 3:
+		*val = val32 >> 24;
+		break;
+	case 2:
+		*val = val32 >> 16;
+		break;
+	case 1:
+		*val = val32 >> 8;
+		break;
+	case 0:
+	default:
+		*val = val32;
+		break;
+	}
+}
+
+/* When the address bit [17:16] is 2'b01, the Configuration access will be
+ * treated as Type 1 and it will be forwarded to external PCIe device.
+ */
+static void __iomem *xgene_pcie_get_cfg_base(struct pci_bus *bus)
+{
+	struct xgene_pcie_port *port = xgene_pcie_bus_to_port(bus);
+	u64 addr = (u64)port->cfg_base;
+
+	if (bus->number >= (port->first_busno + 1))
+		addr |= AXI_EP_CFG_ACCESS;
+
+	return (void *)addr;
+}
+
+/* For Configuration request, RTDID register is used as Bus Number,
+ * Device Number and Function number of the header fields.
+ */
+static void xgene_pcie_set_rtdid_reg(struct pci_bus *bus, uint devfn)
+{
+	struct xgene_pcie_port *port = xgene_pcie_bus_to_port(bus);
+	unsigned int b, d, f;
+	u32 rtdid_val = 0;
+
+	b = bus->number;
+	d = PCI_SLOT(devfn);
+	f = PCI_FUNC(devfn);
+
+	if (bus->number == port->first_busno)
+		rtdid_val = (b << 24) | (d << 19) | (f << 16);
+	else if (bus->number >= (port->first_busno + 1))
+		rtdid_val = (port->first_busno << 24) |
+			    (b << 8) | (d << 3) | f;
+
+	writel(rtdid_val, port->csr_base + RTDID);
+	/* read the register back to ensure flush */
+	readl(port->csr_base + RTDID);
+}
+
+static int xgene_pcie_read_config(struct pci_bus *bus, unsigned int devfn,
+				  int offset, int len, u32 *val)
+{
+	struct xgene_pcie_port *port = xgene_pcie_bus_to_port(bus);
+	void __iomem *addr;
+	u8 val8;
+	u16 val16;
+
+	if ((pci_is_root_bus(bus) && devfn != 0) || !port->link_up)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	xgene_pcie_set_rtdid_reg(bus, devfn);
+	addr = xgene_pcie_get_cfg_base(bus);
+	switch (len) {
+	case 1:
+		xgene_pcie_cfg_in8(addr + offset, &val8);
+		*val = val8;
+		break;
+	case 2:
+		xgene_pcie_cfg_in16(addr + offset, &val16);
+		*val = val16;
+		break;
+	default:
+		xgene_pcie_cfg_in32(addr + offset, val);
+		break;
+	}
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int xgene_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
+				   int offset, int len, u32 val)
+{
+	struct xgene_pcie_port *port = xgene_pcie_bus_to_port(bus);
+	void __iomem *addr;
+
+	if ((pci_is_root_bus(bus) && devfn != 0) || !port->link_up)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	xgene_pcie_set_rtdid_reg(bus, devfn);
+	addr = xgene_pcie_get_cfg_base(bus);
+	switch (len) {
+	case 1:
+		xgene_pcie_cfg_out8(addr + offset, (u8) val);
+		break;
+	case 2:
+		xgene_pcie_cfg_out16(addr + offset, (u16) val);
+		break;
+	default:
+		xgene_pcie_cfg_out32(addr + offset, val);
+		break;
+	}
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops xgene_pcie_ops = {
+	.read = xgene_pcie_read_config,
+	.write = xgene_pcie_write_config
+};
+
+static void xgene_pcie_setup_lanes(struct xgene_pcie_port *port)
+{
+	void *csr_base = port->csr_base;
+	u32 val;
+
+	val = readl(csr_base + BRIDGE_8G_CFG_8);
+	val = eq_pre_cursor_lane0_set(val, 0x7);
+	val = eq_pre_cursor_lane1_set(val, 0x7);
+	writel(val, csr_base + BRIDGE_8G_CFG_8);
+
+	val = readl(csr_base + BRIDGE_8G_CFG_9);
+	val = eq_pre_cursor_lane0_set(val, 0x7);
+	val = eq_pre_cursor_lane1_set(val, 0x7);
+	writel(val, csr_base + BRIDGE_8G_CFG_9);
+
+	val = readl(csr_base + BRIDGE_8G_CFG_10);
+	val = eq_pre_cursor_lane0_set(val, 0x7);
+	val = eq_pre_cursor_lane1_set(val, 0x7);
+	writel(val, csr_base + BRIDGE_8G_CFG_10);
+
+	val = readl(csr_base + BRIDGE_8G_CFG_11);
+	val = eq_pre_cursor_lane0_set(val, 0x7);
+	val = eq_pre_cursor_lane1_set(val, 0x7);
+	writel(val, csr_base + BRIDGE_8G_CFG_11);
+
+	val = readl(csr_base + BRIDGE_8G_CFG_4);
+	val = (val & ~0x30) | (1 << 4);
+	writel(val, csr_base + BRIDGE_8G_CFG_4);
+}
+
+static void xgene_pcie_setup_link(struct xgene_pcie_port *port)
+{
+	void *csr_base = port->csr_base;
+	u32 val;
+
+	val = readl(csr_base + BRIDGE_CFG_14);
+	val |= DIRECT_TO_8GTS_MASK;
+	val |= SUPPORT_5GTS_MASK;
+	val |= SUPPORT_8GTS_MASK;
+	val |= DIRECT_TO_5GTS_MASK;
+	writel(val, csr_base + BRIDGE_CFG_14);
+
+	val = readl(csr_base + BRIDGE_CFG_14);
+	val &= ~ADVT_INFINITE_CREDITS;
+	writel(val, csr_base + BRIDGE_CFG_14);
+
+	val = readl(csr_base + BRIDGE_8G_CFG_0);
+	val |= (val & ~0xf) | 7;
+	val |= (val & ~0xf00) | ((7 << 8) & 0xf00);
+	writel(val, csr_base + BRIDGE_8G_CFG_0);
+
+	val = readl(csr_base + BRIDGE_8G_CFG_0);
+	val |= DWNSTRM_EQ_SKP_PHS_2_3;
+	writel(val, csr_base + BRIDGE_8G_CFG_0);
+}
+
+static void xgene_pcie_program_core(void *csr_base)
+{
+	u32 val;
+
+	val = readl(csr_base + BRIDGE_CFG_0);
+	val |= AER_OPTIONAL_ERROR_EN;
+	writel(val, csr_base + BRIDGE_CFG_0);
+	writel(0x0, csr_base + INTXSTATUSMASK);
+	val = readl(csr_base + BRIDGE_CTRL_1);
+	val = (val & ~0xffff) | XGENE_PCIE_DEV_CTRL;
+	writel(val, csr_base + BRIDGE_CTRL_1);
+}
+
+static u64 xgene_pcie_set_ib_mask(void *csr_base, u32 addr, u32 flags, u64 size)
+{
+	u64 mask = (~(size - 1) & PCI_BASE_ADDRESS_MEM_MASK) | flags;
+	u32 val32 = 0;
+	u32 val;
+
+	val32 = readl(csr_base + addr);
+	val = (val32 & 0x0000ffff) | (lower_32_bits(mask) << 16);
+	writel(val, csr_base + addr);
+
+	val32 = readl(csr_base + addr + 0x04);
+	val = (val32 & 0xffff0000) | (lower_32_bits(mask) >> 16);
+	writel(val, csr_base + addr + 0x04);
+
+	val32 = readl(csr_base + addr + 0x04);
+	val = (val32 & 0x0000ffff) | (upper_32_bits(mask) << 16);
+	writel(val, csr_base + addr + 0x04);
+
+	val32 = readl(csr_base + addr + 0x08);
+	val = (val32 & 0xffff0000) | (upper_32_bits(mask) >> 16);
+	writel(val, csr_base + addr + 0x08);
+
+	return mask;
+}
+
+static void xgene_pcie_poll_linkup(struct xgene_pcie_port *port, u32 *lanes)
+{
+	void *csr_base = port->csr_base;
+	u32 val32;
+	u64 start_time, time;
+
+	/*
+	 * A component enters the LTSSM Detect state within
+	 * 20ms of the end of fundamental core reset.
+	 */
+	msleep(XGENE_LTSSM_DETECT_WAIT);
+	port->link_up = 0;
+	start_time = jiffies;
+	do {
+		val32 = readl(csr_base + PCIECORE_CTLANDSTATUS);
+		if (val32 & LINK_UP_MASK) {
+			port->link_up = 1;
+			port->link_speed = PIPE_PHY_RATE_RD(val32);
+			val32 = readl(csr_base + BRIDGE_STATUS_0);
+			*lanes = val32 >> 26;
+		}
+		time = jiffies_to_msecs(jiffies - start_time);
+	} while ((!port->link_up) || (time <= XGENE_LTSSM_L0_WAIT));
+}
+
+static void xgene_pcie_setup_root_complex(struct xgene_pcie_port *port)
+{
+	void *csr_base = port->csr_base;
+	u32 val;
+
+	val = (XGENE_PCIE_DEVICEID << 16) | XGENE_PCIE_VENDORID;
+	writel(val, csr_base + BRIDGE_CFG_0);
+
+	val = readl(csr_base + BRIDGE_CFG_1);
+	val &= ~CLASS_CODE_MASK;
+	val |= PCI_CLASS_BRIDGE_PCI << 16;
+	writel(val, csr_base + BRIDGE_CFG_1);
+
+	val = readl(csr_base + BRIDGE_CFG_14);
+	val |= SWITCH_PORT_MODE_MASK;
+	val &= ~PM_FORCE_RP_MODE_MASK;
+	writel(val, csr_base + BRIDGE_CFG_14);
+	xgene_pcie_setup_link(port);
+	xgene_pcie_setup_lanes(port);
+	val = readl(csr_base + BRIDGE_CTRL_5);
+	val &= ~DEVICE_PORT_TYPE_MASK;
+	val |= XGENE_PORT_TYPE_RC;
+	writel(val, csr_base + BRIDGE_CTRL_5);
+
+	val = readl(csr_base + BRIDGE_CTRL_2);
+	val |= ENABLE_ASPM;
+	writel(val, csr_base + BRIDGE_CTRL_2);
+
+	val = readl(csr_base + BRIDGE_CFG_32);
+	writel(val | (1 << 19), csr_base + BRIDGE_CFG_32);
+}
+
+/* Return 0 on success */
+static int xgene_pcie_init_ecc(struct xgene_pcie_port *port)
+{
+	void *csr_base = port->csr_base;
+	int timeout = XGENE_PCIE_TIMEOUT;
+	u32 val;
+
+	val = readl(csr_base + MEM_RAM_SHUTDOWN);
+	if (val == 0)
+		return 0;
+	writel(0x0, csr_base + MEM_RAM_SHUTDOWN);
+	do {
+		val = readl(csr_base + BLOCK_MEM_RDY);
+		udelay(1);
+	} while ((val != BLOCK_MEM_RDY_VAL) && timeout--);
+
+	return !(timeout > 0);
+}
+
+static int xgene_pcie_init_port(struct xgene_pcie_port *port)
+{
+	int rc;
+
+	port->clk = clk_get(port->dev, NULL);
+	if (IS_ERR_OR_NULL(port->clk)) {
+		dev_err(port->dev, "clock not available\n");
+		return -ENODEV;
+	}
+
+	rc = clk_prepare_enable(port->clk);
+	if (rc) {
+		dev_err(port->dev, "clock enable failed\n");
+		return rc;
+	}
+
+	rc = xgene_pcie_init_ecc(port);
+	if (rc) {
+		dev_err(port->dev, "memory init failed\n");
+		return rc;
+	}
+
+	return 0;
+}
+
+struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus)
+{
+	struct xgene_pcie_port *port = xgene_pcie_bus_to_port(bus);
+
+	return of_node_get(port->node);
+}
+
+static void xgene_pcie_fixup_bridge(struct pci_dev *dev)
+{
+	int i;
+
+	/* Hide the PCI host BARs from the kernel as their content doesn't
+	 * fit well in the resource management
+	 */
+	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+		dev->resource[i].start = dev->resource[i].end = 0;
+		dev->resource[i].flags = 0;
+	}
+	dev_info(&dev->dev, "Hiding X-Gene pci host bridge resources %s\n",
+		 pci_name(dev));
+}
+DECLARE_PCI_FIXUP_HEADER(XGENE_PCIE_VENDORID, XGENE_PCIE_DEVICEID,
+			 xgene_pcie_fixup_bridge);
+
+static void xgene_pcie_setup_primary_bus(struct xgene_pcie_port *port,
+					 u32 first_busno, u32 last_busno)
+{
+	u32 val;
+	void *cfg_addr = port->cfg_base;
+
+	val = readl(cfg_addr + PCI_PRIMARY_BUS);
+	val &= ~PCI_PRIMARY_BUS_MASK;
+	val |= (last_busno << 16) | ((first_busno + 1) << 8) | (first_busno);
+	writel(val, cfg_addr + PCI_PRIMARY_BUS);
+}
+
+/*
+ * read configuration values from DTS
+ */
+static int xgene_pcie_read_dts_config(struct xgene_pcie_port *port)
+{
+	struct device_node *np = port->node;
+	struct resource csr_res;
+	struct resource cfg_res;
+
+	/* Get CSR space registers address */
+	if (of_address_to_resource(np, 0, &csr_res))
+		return -EINVAL;
+
+	port->csr_base = devm_ioremap_nocache(port->dev, csr_res.start,
+					      resource_size(&csr_res));
+	if (port->csr_base == NULL)
+		return -ENOMEM;
+
+	/* Get CFG space registers address */
+	if (of_address_to_resource(np, 1, &cfg_res))
+		return -EINVAL;
+
+	port->cfg_addr = cfg_res.start;
+	port->cfg_base = devm_ioremap_nocache(port->dev, cfg_res.start,
+					      resource_size(&cfg_res));
+	if (port->csr_base == NULL)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void xgene_pcie_setup_ob_reg(struct xgene_pcie_port *port,
+				    u32 addr, u32 restype)
+{
+	struct resource *res = NULL;
+	void *base = port->csr_base + addr;
+	resource_size_t size;
+	u64 cpu_addr = 0;
+	u64 pci_addr = 0;
+	u64 mask = 0;
+	u32 min_size = 0;
+	u32 flag = EN_REG;
+
+	switch (restype) {
+	case IORESOURCE_MEM:
+		res = &port->mem.res;
+		pci_addr = port->mem.pci_addr;
+		min_size = SZ_128M;
+		break;
+	case IORESOURCE_IO:
+		res = &port->io.res;
+		pci_addr = port->io.pci_addr;
+		min_size = 128;
+		flag |= OB_LO_IO;
+		break;
+	}
+	size = resource_size(res);
+	if (size >= min_size)
+		mask = ~(size - 1) | flag;
+	else
+		dev_warn(port->dev, "res size 0x%llx less than minimum 0x%x\n",
+			 (u64)size, min_size);
+	cpu_addr = res->start;
+	writel(lower_32_bits(cpu_addr), base);
+	writel(upper_32_bits(cpu_addr), base + 0x04);
+	writel(lower_32_bits(mask), base + 0x08);
+	writel(upper_32_bits(mask), base + 0x0c);
+	writel(lower_32_bits(pci_addr), base + 0x10);
+	writel(upper_32_bits(pci_addr), base + 0x14);
+}
+
+static void xgene_pcie_setup_cfg_reg(struct xgene_pcie_port *port)
+{
+	void *csr_base = port->csr_base;
+	u64 addr = port->cfg_addr;
+
+	writel(lower_32_bits(addr), csr_base + CFGBARL);
+	writel(upper_32_bits(addr), csr_base + CFGBARH);
+	writel(EN_REG, csr_base + CFGCTL);
+}
+
+static int xgene_pcie_parse_map_ranges(struct xgene_pcie_port *port)
+{
+	struct device_node *np = port->node;
+	struct of_pci_range range;
+	struct of_pci_range_parser parser;
+	struct device *dev = port->dev;
+
+	if (of_pci_range_parser_init(&parser, np)) {
+		dev_err(dev, "missing ranges property\n");
+		return -EINVAL;
+	}
+
+	/* Get the I/O, memory, config ranges from DT */
+	for_each_of_pci_range(&parser, &range) {
+		struct resource *res = NULL;
+		u64 restype = range.flags & IORESOURCE_TYPE_BITS;
+		u64 end = range.cpu_addr + range.size - 1;
+		dev_dbg(port->dev, "0x%08x 0x%016llx..0x%016llx -> 0x%016llx\n",
+			range.flags, range.cpu_addr, end, range.pci_addr);
+
+		switch (restype) {
+		case IORESOURCE_IO:
+			res = &port->io.res;
+			port->io.pci_addr = range.pci_addr;
+			of_pci_range_to_resource(&range, np, res);
+			xgene_pcie_setup_ob_reg(port, OMR1BARL, restype);
+			break;
+		case IORESOURCE_MEM:
+			res = &port->mem.res;
+			port->mem.pci_addr = range.pci_addr;
+			of_pci_range_to_resource(&range, np, res);
+			xgene_pcie_setup_ob_reg(port, OMR2BARL, restype);
+			break;
+		default:
+			dev_err(dev, "invalid io resource!");
+			return -EINVAL;
+		}
+	}
+	xgene_pcie_setup_cfg_reg(port);
+	return 0;
+}
+
+static int pci_dma_range_parser_init(struct of_pci_range_parser *parser,
+				     struct device_node *node)
+{
+	const int na = 3, ns = 2;
+	int rlen;
+
+	parser->node = node;
+	parser->pna = of_n_addr_cells(node);
+	parser->np = parser->pna + na + ns;
+
+	parser->range = of_get_property(node, "dma-ranges", &rlen);
+	if (parser->range == NULL)
+		return -ENOENT;
+
+	parser->end = parser->range + rlen / sizeof(__be32);
+
+	return 0;
+}
+
+static void xgene_pcie_setup_pims(void *addr, u64 pim, u64 size)
+{
+	writel(lower_32_bits(pim), addr);
+	writel(upper_32_bits(pim) | EN_COHERENCY, addr + 0x04);
+	writel(lower_32_bits(size), addr + 0x10);
+	writel(upper_32_bits(size), addr + 0x14);
+}
+
+static void xgene_pcie_setup_ib_reg(struct xgene_pcie_port *port,
+				    struct of_pci_range *range, u64 restype,
+				    u32 region)
+{
+	void *csr_base = port->csr_base;
+	void *cfg_base = port->cfg_base;
+	void *bar_addr;
+	void *pim_addr;
+	u64 cpu_addr = range->cpu_addr;
+	u64 pci_addr = range->pci_addr;
+	u64 size = range->size;
+	u64 mask = ~(size - 1) | EN_REG;
+	u32 flags = PCI_BASE_ADDRESS_MEM_TYPE_64;
+	u32 bar_low;
+
+	if (restype == PCI_BASE_ADDRESS_MEM_PREFETCH)
+		flags |= PCI_BASE_ADDRESS_MEM_PREFETCH;
+
+	bar_low = pcie_bar_low_val((u32)cpu_addr, flags);
+	switch (region) {
+	case 0:
+		xgene_pcie_set_ib_mask(csr_base, BRIDGE_CFG_4, flags, size);
+		bar_addr = cfg_base + PCI_BASE_ADDRESS_0;
+		writel(bar_low, bar_addr);
+		writel(upper_32_bits(cpu_addr), bar_addr + 0x4);
+		pim_addr = csr_base + PIM1_1L;
+		break;
+	case 1:
+		bar_addr = csr_base + IBAR2;
+		writel(bar_low, bar_addr);
+		writel(lower_32_bits(mask), csr_base + IR2MSK);
+		pim_addr = csr_base + PIM2_1L;
+		break;
+	case 2:
+		bar_addr = csr_base + IBAR3L;
+		writel(bar_low, bar_addr);
+		writel(upper_32_bits(cpu_addr), bar_addr + 0x4);
+		writel(lower_32_bits(mask), csr_base + IR3MSKL);
+		writel(upper_32_bits(mask), csr_base + IR3MSKL + 0x4);
+		pim_addr = csr_base + PIM3_1L;
+		break;
+	}
+	xgene_pcie_setup_pims(pim_addr, pci_addr, size);
+}
+
+/* X-Gene PCIe support maximum 3 inbound memory regions
+ * This function helps to select a region based on size of region
+ */
+static int xgene_pcie_select_ib_reg(u64 size)
+{
+	static u8 ib_reg_mask;
+
+	if ((size > 4) && (size < SZ_16M) && !(ib_reg_mask & (1 << 1))) {
+		ib_reg_mask |= (1 << 1);
+		return 1;
+	}
+
+	if ((size > SZ_1K) && (size < SZ_1T) && !(ib_reg_mask & (1 << 0))) {
+		ib_reg_mask |= (1 << 0);
+		return 0;
+	}
+
+	if ((size > SZ_1M) && (size < SZ_1T) && !(ib_reg_mask & (1 << 2))) {
+		ib_reg_mask |= (1 << 2);
+		return 2;
+	}
+	return -EINVAL;
+}
+
+static int xgene_pcie_parse_map_dma_ranges(struct xgene_pcie_port *port)
+{
+	struct device_node *np = port->node;
+	struct of_pci_range range;
+	struct of_pci_range_parser parser;
+	struct device *dev = port->dev;
+	int region;
+
+	if (pci_dma_range_parser_init(&parser, np)) {
+		dev_err(dev, "missing dma-ranges property\n");
+		return -EINVAL;
+	}
+
+	/* Get the dma-ranges from DT */
+	for_each_of_pci_range(&parser, &range) {
+		u64 restype = range.flags & IORESOURCE_TYPE_BITS;
+		u64 end = range.cpu_addr + range.size - 1;
+		dev_dbg(port->dev, "0x%08x 0x%016llx..0x%016llx -> 0x%016llx\n",
+			range.flags, range.cpu_addr, end, range.pci_addr);
+		region = xgene_pcie_select_ib_reg(range.size);
+		if (region == -EINVAL) {
+			dev_warn(port->dev, "invalid pcie dma-range config\n");
+			continue;
+		}
+		xgene_pcie_setup_ib_reg(port, &range, restype, region);
+	}
+	return 0;
+}
+
+static int xgene_pcie_setup(int nr, struct pci_sys_data *sys)
+{
+	struct xgene_pcie_port *pp = xgene_pcie_sys_to_port(sys);
+
+	if (pp == NULL)
+		return 0;
+
+	sys->mem_offset = pp->mem.res.start - pp->mem.pci_addr;
+	pci_add_resource_offset(&sys->resources, &pp->mem.res,
+				sys->mem_offset);
+	return 1;
+}
+
+static struct pci_bus __init *xgene_pcie_scan_bus(int nr,
+						  struct pci_sys_data *sys)
+{
+	struct xgene_pcie_port *pp = xgene_pcie_sys_to_port(sys);
+
+	pp->first_busno = sys->busnr;
+	xgene_pcie_setup_primary_bus(pp, sys->busnr, 0xff);
+	return pci_scan_root_bus(NULL, sys->busnr, &xgene_pcie_ops,
+				 sys, &sys->resources);
+}
+
+static struct hw_pci xgene_pcie_hw __initdata = {
+	.nr_controllers = XGENE_PCIE_MAX_PORTS,
+	.setup = xgene_pcie_setup,
+	.scan = xgene_pcie_scan_bus,
+	.map_irq = of_irq_parse_and_map_pci,
+};
+
+static int __init xgene_pcie_probe_bridge(struct platform_device *pdev)
+{
+	struct device_node *np = of_node_get(pdev->dev.of_node);
+	struct xgene_pcie_port *port;
+	static int index;
+	u32 lanes = 0;
+	int ret;
+
+	port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
+	if (port == NULL)
+		return -ENOMEM;
+	port->node = np;
+	port->dev = &pdev->dev;
+
+	ret = xgene_pcie_read_dts_config(port);
+	if (ret)
+		return ret;
+
+	ret = xgene_pcie_init_port(port);
+	if (ret)
+		goto skip;
+	xgene_pcie_program_core(port->csr_base);
+	xgene_pcie_setup_root_complex(port);
+	ret = xgene_pcie_parse_map_ranges(port);
+	if (ret)
+		goto skip;
+	ret = xgene_pcie_parse_map_dma_ranges(port);
+	if (ret)
+		goto skip;
+	xgene_pcie_poll_linkup(port, &lanes);
+skip:
+	if (!port->link_up)
+		dev_info(port->dev, "(rc) link down\n");
+	else
+		dev_info(port->dev, "(rc) x%d gen-%d link up\n",
+				lanes, port->link_speed + 1);
+#ifdef CONFIG_PCI_DOMAINS
+	xgene_pcie_hw.domain++;
+#endif
+	xgene_pcie_hw.private_data[index++] = port;
+	platform_set_drvdata(pdev, port);
+	return 0;
+}
+
+static const struct of_device_id xgene_pcie_match_table[] __initconst = {
+	{.compatible = "apm,xgene-pcie",},
+	{},
+};
+
+static struct platform_driver xgene_pcie_driver = {
+	.driver = {
+		   .name = "xgene-pcie",
+		   .owner = THIS_MODULE,
+		   .of_match_table = of_match_ptr(xgene_pcie_match_table),
+		  },
+};
+
+static int __init xgene_pcie_init(void)
+{
+	void *private;
+	int ret;
+
+	pr_info("X-Gene: PCIe driver\n");
+
+	/* allocate private data to keep xgene_pcie_port information */
+	private = kzalloc((XGENE_PCIE_MAX_PORTS * sizeof(void *)), GFP_KERNEL);
+	if (private == NULL)
+		return -ENOMEM;
+	xgene_pcie_hw.private_data = private;
+	ret = platform_driver_probe(&xgene_pcie_driver,
+				    xgene_pcie_probe_bridge);
+	if (ret)
+		return ret;
+	pci_common_init(&xgene_pcie_hw);
+	return 0;
+}
+
+module_init(xgene_pcie_init);
+
+MODULE_AUTHOR("Tanmay Inamdar <tinamdar@apm.com>");
+MODULE_DESCRIPTION("APM X-Gene PCIe driver");
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.5

^ permalink raw reply related

* [RFC PATCH V2 0/4] APM X-Gene PCIe controller
From: Tanmay Inamdar @ 2014-01-14 23:34 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds support for AppliedMicro X-Gene PCIe host controller. The
driver is tested on X-Gene platform with different gen1/2/3 PCIe endpoint
cards.

X-Gene PCIe controller driver has depedency on the pcie arch support for
arm64. The arm64 pcie arch support is not yet part of mainline Linux kernel
and approach for arch support is under discussion with arm64 maintainers.
The reference patch can be found here --> https://lkml.org/lkml/2013/10/23/244

If someone wishes to test PCIe on X-Gene, arch support patch must be applied
before the patches in this patch set.

changes since V1:
1. added PCI domain support
2. reading cpu and pci addresses from device tree to configure regions.
3. got rid of unnecessary wrappers for readl and writel.
4. got rid of endpoint configuration code.
5. added 'dma-ranges' property support to read inbound region configuration.
6. renamed host driver file to 'pci-xgene.c' from 'pcie-xgene.c'
7. dropped 'clock-names' property from bindings
8. added comments whereever requested.

Tanmay Inamdar (4):
  pci: APM X-Gene PCIe controller driver
  arm64:dts: APM X-Gene PCIe device tree nodes
  dt-bindings: pci: xgene pcie device tree bindings
  MAINTAINERS: entry for APM X-Gene PCIe host driver

 .../devicetree/bindings/pci/xgene-pcie.txt         |   45 +
 MAINTAINERS                                        |    7 +
 arch/arm64/boot/dts/apm-mustang.dts                |    4 +
 arch/arm64/boot/dts/apm-storm.dtsi                 |  144 +++
 drivers/pci/host/Kconfig                           |   10 +
 drivers/pci/host/Makefile                          |    1 +
 drivers/pci/host/pci-xgene.c                       |  934 ++++++++++++++++++++
 7 files changed, 1145 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pci/xgene-pcie.txt
 create mode 100644 drivers/pci/host/pci-xgene.c

-- 
1.7.9.5

^ permalink raw reply

* [GIT PULL] Allwinner DT changes for 3.14, take 2
From: Kevin Hilman @ 2014-01-14 23:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140107231033.GA18548@lukather>

Maxime Ripard <maxime.ripard@free-electrons.com> writes:

> Hi Arnd, Kevin, Olof,
>
> Please pull the following changes on top of the previous pull request.
>
> Thanks!
> Maxime
>
> The following changes since commit 81ee429ffdd021626bf191bb8a3ae886dd94adcc:
>
>   ARM: sun6i: dt: Add IP needed to bring up the additional cores (2013-12-16 21:15:12 +0100)
>
> are available in the git repository at:
>
>   https://github.com/mripard/linux.git tags/sunxi-dt-for-3.14-2
>
> for you to fetch changes up to 6267355f0e513bed9a5009924abc7a1e7de22ab3:
>
>   arm: sun7i: cubietruck: Enable the i2c controllers (2014-01-07 23:39:19 +0100)
>
> ----------------------------------------------------------------
> Second round of DT additions for 3.14
>
> Mostly:
>   - Addition of the missing PLLs and module clocks
>   - Addition of the external clocks
>   - Addition of the touchscreen controler
>   - I2C nodes of the Cubietruck
>
> ----------------------------------------------------------------

Applied to next/dt.

Thanks,

Kevin

^ permalink raw reply

* [GIT PULL] Allwinner core changes for 3.14, take 2
From: Kevin Hilman @ 2014-01-14 23:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140107230848.GA18498@lukather>

Maxime Ripard <maxime.ripard@free-electrons.com> writes:

> Hi Arnd, Kevin, Olof,
>
> Please pull the following patches on top of the previous pull request.
>
> Thanks!
>
> The following changes since commit 73346794b48237b7b4c2a5c02b12e3c4f1da7551:
>
>   ARM: sun6i: Add SMP support for the Allwinner A31 (2013-12-16 21:33:41 +0100)
>
> are available in the git repository at:
>
>   https://github.com/mripard/linux.git tags/sunxi-core-for-3.14-2
>
> for you to fetch changes up to 75cac6abe756fde529a000e725dceed2b908f61a:
>
>   ARM: sunxi: select ARM_PSCI (2014-01-01 23:58:17 +0100)
>
> ----------------------------------------------------------------
> Second round of core additions for the Allwinner SoCs
>
> Fixes to select missing configuration options, and update of the maintainer
> file.
>
> ----------------------------------------------------------------

Applied to next/soc.

Thanks,

Kevin

^ permalink raw reply

* [PATCH v2] ARM: OMAP4460: cpuidle: Extend PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD on cpuidle
From: Santosh Shilimkar @ 2014-01-14 23:28 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAGa+x863_MQ22h+U=KtK++3aG2F_X4x57Xtfe16GYXKNiaWX4A@mail.gmail.com>

On Tuesday 14 January 2014 04:26 PM, Kevin Hilman wrote:
> On Fri, Nov 15, 2013 at 8:12 AM, Santosh Shilimkar
> <santosh.shilimkar@ti.com> wrote:
>> On Friday 15 November 2013 11:11 AM, Tony Lindgren wrote:
>>> * Taras Kondratiuk <taras.kondratiuk@linaro.org> [131115 08:03]:
>>>> On 11/15/2013 05:36 PM, Tony Lindgren wrote:
>>>>> * Tony Lindgren <tony@atomide.com> [131114 10:36]:
>>>>>> * Grygorii Strashko <grygorii.strashko@ti.com> [131022 12:09]:
>>>>>>> The same workaround as ff999b8a0983ee15668394ed49e38d3568fc6859
>>>>>>> "ARM: OMAP4460: Workaround for ROM bug because of CA9 r2pX GIC ..."
>>>>>>> need to be applied not only when system is booting, but when MPUSS hits
>>>>>>> OSWR state through CPUIdle too. Without this WA the same issue is
>>>>>>> reproduced now on boards PandaES and Tablet/Blaze with SOM OMAP4460
>>>>>>> when CONFIG_CPU_IDLE is enabled.
>>>>>>> After MPUSS has enterred OSWR and waken up:
>>>>>>> - GIC distributor became disabled forever
>>>>>>> - scheduling is not performed any more
>>>>>>>
>>>>>>> Cc: Kevin Hilman <khilman@linaro.org>
>>>>>>> Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
>>>>>>> Reported-by: Taras Kondratiuk <taras.kondratiuk@linaro.org>
>>>>>>> Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
>>>>>>
>>>>>> Applying into omap-for-v3.13/fixes thanks.
>>>>>
>>>>> Hmm looks like this breaks the build with randconfigs at least
>>>>> with the attached .config, so dropping for now.
>>>>
>>>> Hi Tony
>>>> Have you forgot to attach .config?
>>>
>>> Oops, sorry looks like I removed it already as I rebuilt the tree
>>> and started a new set of randconfig build tests.
>>>
>>>>> arch/arm/mach-omap2/built-in.o: In function `omap_enter_idle_coupled':
>>>>> :(.text+0xb48c): undefined reference to `pm44xx_errata'
>>>>
>>>> I assume that .config doesn't have CONFIG_SMP enabled while
>>>> pm44xx_errata is defined in omap-smp.c.
>>>> I think it should be a separate patch to move pm44xx_errata somewhere
>>>> else, so this patch will remain the same.
>>>
>>> Yes something like that probably. Sounds like that should be then
>>> patches before this fix.
>>>
>>>> Btw, do we need omap_enter_idle_coupled() in UP?
>>>
>>> That should be checked, am43xx may need it.
>>>
>> Nope. omap_enter_idle_coupled() is needed only for SMP
>> systems. UP don't need couple idle functionality as
>> such.
> 
> So what's the status of this fix and dependencies?
> 
> Both linux-next[1] and arm-soc/for-next[2] are failing boot tests on
> omap4460/panda-es because multi_v7_defconfig now has CPUidle enabled
> by default.
> 
I think Taras needs to refresh the patch based on discussion
and then it can be merged.

> 
> [1] http://lists.linaro.org/pipermail/kernel-build-reports/2014-January/001891.html
> [2] http://lists.linaro.org/pipermail/kernel-build-reports/2014-January/001898.html
> 

^ permalink raw reply

* [Intel-gfx] [PATCH 1/2] drm: share drm_add_fake_info_node
From: Daniel Vetter @ 2014-01-14 23:25 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1389708847-25038-1-git-send-email-benjamin.widawsky@intel.com>

On Tue, Jan 14, 2014 at 06:14:06AM -0800, Ben Widawsky wrote:
> Both i915 and Armada had the exact same implementation. For an upcoming
> patch, I'd like to call this function from two different source files in
> i915, and having it available externally helps there too.
> 
> While moving, add 'debugfs_' to the name in order to match the other drm
> debugfs helper functions.
> 
> Cc: linux-arm-kernel at lists.infradead.org
> Cc: intel-gfx at lists.freedesktop.org
> Signed-off-by: Ben Widawsky <ben@bwidawsk.net>

drm_debugfs_create_files in drm_debugfs.c has the almost same code again.
Now the problem here is that the interface is a bit botched up, since all
the users in i915 and armada actaully faile to clean up teh debugfs dentry
if drm_add_fake_info_node.

So I think the right approach is to extrace a new drm_debugfs_create_node
helper which is used by i915, armada and drm_debugfs_create_files. Also I
think it's better to split this up into a drm core patch and then
i915/armada driver patches, for easier merging.
-Daniel

> ---
>  drivers/gpu/drm/armada/armada_debugfs.c | 24 +-----------------------
>  drivers/gpu/drm/drm_debugfs.c           | 24 ++++++++++++++++++++++++
>  drivers/gpu/drm/i915/i915_debugfs.c     | 32 +++-----------------------------
>  include/drm/drmP.h                      |  9 +++++++++
>  4 files changed, 37 insertions(+), 52 deletions(-)
> 
> diff --git a/drivers/gpu/drm/armada/armada_debugfs.c b/drivers/gpu/drm/armada/armada_debugfs.c
> index 471e456..02f2978 100644
> --- a/drivers/gpu/drm/armada/armada_debugfs.c
> +++ b/drivers/gpu/drm/armada/armada_debugfs.c
> @@ -107,28 +107,6 @@ static struct drm_info_list armada_debugfs_list[] = {
>  };
>  #define ARMADA_DEBUGFS_ENTRIES ARRAY_SIZE(armada_debugfs_list)
>  
> -static int drm_add_fake_info_node(struct drm_minor *minor, struct dentry *ent,
> -	const void *key)
> -{
> -	struct drm_info_node *node;
> -
> -	node = kmalloc(sizeof(struct drm_info_node), GFP_KERNEL);
> -	if (node == NULL) {
> -		debugfs_remove(ent);
> -		return -ENOMEM;
> -	}
> -
> -	node->minor = minor;
> -	node->dent = ent;
> -	node->info_ent = (void *) key;
> -
> -	mutex_lock(&minor->debugfs_lock);
> -	list_add(&node->list, &minor->debugfs_list);
> -	mutex_unlock(&minor->debugfs_lock);
> -
> -	return 0;
> -}
> -
>  static int armada_debugfs_create(struct dentry *root, struct drm_minor *minor,
>  	const char *name, umode_t mode, const struct file_operations *fops)
>  {
> @@ -136,7 +114,7 @@ static int armada_debugfs_create(struct dentry *root, struct drm_minor *minor,
>  
>  	de = debugfs_create_file(name, mode, root, minor->dev, fops);
>  
> -	return drm_add_fake_info_node(minor, de, fops);
> +	return drm_debugfs_add_fake_info_node(minor, de, fops);
>  }
>  
>  int armada_drm_debugfs_init(struct drm_minor *minor)
> diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c
> index b4b51d4..1edaac0 100644
> --- a/drivers/gpu/drm/drm_debugfs.c
> +++ b/drivers/gpu/drm/drm_debugfs.c
> @@ -237,5 +237,29 @@ int drm_debugfs_cleanup(struct drm_minor *minor)
>  	return 0;
>  }
>  
> +int drm_debugfs_add_fake_info_node(struct drm_minor *minor,
> +				   struct dentry *ent,
> +				   const void *key)
> +{
> +	struct drm_info_node *node;
> +
> +	node = kmalloc(sizeof(*node), GFP_KERNEL);
> +	if (node == NULL) {
> +		debugfs_remove(ent);
> +		return -ENOMEM;
> +	}
> +
> +	node->minor = minor;
> +	node->dent = ent;
> +	node->info_ent = (void *) key;
> +
> +	mutex_lock(&minor->debugfs_lock);
> +	list_add(&node->list, &minor->debugfs_list);
> +	mutex_unlock(&minor->debugfs_lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(drm_debugfs_add_fake_info_node);
> +
>  #endif /* CONFIG_DEBUG_FS */
>  
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> index 430eb3e..f2ef30c 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -51,32 +51,6 @@ static const char *yesno(int v)
>  	return v ? "yes" : "no";
>  }
>  
> -/* As the drm_debugfs_init() routines are called before dev->dev_private is
> - * allocated we need to hook into the minor for release. */
> -static int
> -drm_add_fake_info_node(struct drm_minor *minor,
> -		       struct dentry *ent,
> -		       const void *key)
> -{
> -	struct drm_info_node *node;
> -
> -	node = kmalloc(sizeof(*node), GFP_KERNEL);
> -	if (node == NULL) {
> -		debugfs_remove(ent);
> -		return -ENOMEM;
> -	}
> -
> -	node->minor = minor;
> -	node->dent = ent;
> -	node->info_ent = (void *) key;
> -
> -	mutex_lock(&minor->debugfs_lock);
> -	list_add(&node->list, &minor->debugfs_list);
> -	mutex_unlock(&minor->debugfs_lock);
> -
> -	return 0;
> -}
> -
>  static int i915_capabilities(struct seq_file *m, void *data)
>  {
>  	struct drm_info_node *node = (struct drm_info_node *) m->private;
> @@ -2148,7 +2122,7 @@ static int i915_pipe_crc_create(struct dentry *root, struct drm_minor *minor,
>  	if (!ent)
>  		return -ENOMEM;
>  
> -	return drm_add_fake_info_node(minor, ent, info);
> +	return drm_debugfs_add_fake_info_node(minor, ent, info);
>  }
>  
>  static const char * const pipe_crc_sources[] = {
> @@ -3164,7 +3138,7 @@ static int i915_forcewake_create(struct dentry *root, struct drm_minor *minor)
>  	if (!ent)
>  		return -ENOMEM;
>  
> -	return drm_add_fake_info_node(minor, ent, &i915_forcewake_fops);
> +	return drm_debugfs_add_fake_info_node(minor, ent, &i915_forcewake_fops);
>  }
>  
>  static int i915_debugfs_create(struct dentry *root,
> @@ -3182,7 +3156,7 @@ static int i915_debugfs_create(struct dentry *root,
>  	if (!ent)
>  		return -ENOMEM;
>  
> -	return drm_add_fake_info_node(minor, ent, fops);
> +	return drm_debugfs_add_fake_info_node(minor, ent, fops);
>  }
>  
>  static const struct drm_info_list i915_debugfs_list[] = {
> diff --git a/include/drm/drmP.h b/include/drm/drmP.h
> index 2fe9b5d..5788fb1 100644
> --- a/include/drm/drmP.h
> +++ b/include/drm/drmP.h
> @@ -1471,6 +1471,9 @@ extern int drm_debugfs_create_files(const struct drm_info_list *files,
>  extern int drm_debugfs_remove_files(const struct drm_info_list *files,
>  				    int count, struct drm_minor *minor);
>  extern int drm_debugfs_cleanup(struct drm_minor *minor);
> +extern int drm_debugfs_add_fake_info_node(struct drm_minor *minor,
> +					  struct dentry *ent,
> +					  const void *key);
>  #else
>  static inline int drm_debugfs_init(struct drm_minor *minor, int minor_id,
>  				   struct dentry *root)
> @@ -1495,6 +1498,12 @@ static inline int drm_debugfs_cleanup(struct drm_minor *minor)
>  {
>  	return 0;
>  }
> +static int drm_debugfs_add_fake_info_node(struct drm_minor *minor,
> +					  struct dentry *ent,
> +					  const void *key)
> +{
> +	return 0;
> +}
>  #endif
>  
>  				/* Info file support */
> -- 
> 1.8.5.2
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply

* [PATCH v2 0/3] Fix SATA disk hotplug for Armada 370/XP SoCs
From: Simon Guinot @ 2014-01-14 23:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140114155945.GQ19878@titan.lakedaemon.net>

On Tue, Jan 14, 2014 at 10:59:45AM -0500, Jason Cooper wrote:
> Simon,
> 
> On Tue, Jan 14, 2014 at 04:48:34PM +0100, Simon Guinot wrote:
> > On Tue, Jan 14, 2014 at 10:14:04AM -0500, Jason Cooper wrote:
> > > Simon,
> > > 
> > > On Tue, Jan 14, 2014 at 03:50:04PM +0100, Simon Guinot wrote:
> > > > Hello,
> > > > 
> > > > This patch series fixes a SATA disk hotplug issue for the Armada 370/XP
> > > > SoCs: once a disk is removed from a SATA port, then the re-plug events
> > > > are not detected by the sata_mv driver.
> > > > 
> > > > This should be applied to the -stable kernels 3.10 and onwards. 
> > > 
> > > Please add a 'Fixes: <commit-hash> (oneline)' tag below the Cc: stable
> > > tags.  It looks like the sata_mv binding and the Armada 370 DT booting
> > > were both introduced in v3.6, so I would probably use:
> > > 
> > > Fixes: 9ae6f740b49f (arm: mach-mvebu: add support for Armada 370 and Armada XP with DT)
> > 
> > Hi Jason,
> > 
> > I am not comfortable with this "Fixes: commit_id" notation. It states
> > that the patch fixes a regression introduced by a given commit. This
> > hardly makes sense to me because obviously the hotplug issue has not
> > been introduced by:
> > 
> > "arm: mach-mvebu: add support for Armada 370 and Armada XP with DT".
> > 
> > I know that the purpose is purely administrative, but it is kind of
> > weird...
> 
> True, the wording may not be the best, but the goal is to make it easier
> to do a 'tag --contains' search.  We could call it
> 
> Repair-Something-Broken-Since-Introduced-by:
> 
> in this case ;-)
> 
> > > Is there a specific reason you say v3.10?
> > 
> > I could have said nothing as well.
> > 
> > As stable kernel older than 3.10 are no longer maintained, I think
> > we don't need to point out a specific commit as a -stable target.
> > Simply Cc'ing -stable without any extra informations should be good
> > enough.
> 
> The reason I ask is that I'd like to know if, in debugging this issue,
> you discovered that the fix was not needed before v3.10 (hypothetically,
> say because sata hotplug was added in v3.10).
> 
> The linux-stable team isn't the only people who find this information
> useful.  Distros maintaining older kernels would find it very helpful
> when going through -stable patches to know easily if a patch should be
> backported further, say to v3.8.

The patches may effectively apply against a 3.6 kernel but who is going
to embed a such kernel on an Armada-based board ?

IMO, stabilize the Armada support for kernels older than 3.10 is a waste
of time, for you, for the -stable maintainers and for me. Some important
features (for Armada SoCs) are missing on this kernels. Then I don't
think that someone is going to use a kernel older than 3.10 with an
Armada-based board.

But anyway, it is not up to me and I have hopefully added all the needed
-stable informations to the v3 patch series.

Simon
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140115/12e03481/attachment-0001.sig>

^ permalink raw reply

* [PATCH] ARM: sunxi: Add driver for sunxi usb phy
From: Hans de Goede @ 2014-01-14 22:58 UTC (permalink / raw)
  To: linux-arm-kernel

The Allwinner A1x / A2x SoCs have 2 or 3 usb phys which are all accessed
through a single set of registers. Besides this there are also some other
phy related bits which need poking, which are per phy, but shared between the
ohci and ehci controllers, so these are also controlled from this new phy
driver.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 .../devicetree/bindings/phy/sun4i-usb-phy.txt      |  26 ++
 drivers/phy/Kconfig                                |  11 +
 drivers/phy/Makefile                               |   1 +
 drivers/phy/phy-sun4i-usb.c                        | 318 +++++++++++++++++++++
 4 files changed, 356 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
 create mode 100644 drivers/phy/phy-sun4i-usb.c

diff --git a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
new file mode 100644
index 0000000..6c54b3b
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
@@ -0,0 +1,26 @@
+Allwinner sun4i USB PHY
+-----------------------
+
+Required properties:
+- compatible : should be one of "allwinner,sun4i-a10-usb-phy",
+  "allwinner,sun5i-a13-usb-phy" or "allwinner,sun7i-a20-usb-phy"
+- reg : 2 or 3 register offset + length pairs, 1 phy base reg pair +
+  1 pair for the pmu-irq register of each hcd
+- #phy-cells : from the generic phy bindings, must be 1
+
+Optional properties:
+- clocks : phandle + clock specifier for the phy clock
+- clock-names : "usb_phy"
+- resets : a list of phandle + reset specifier pairs
+- reset-names : "usb0_reset", "usb1_reset", and / or "usb2_reset"
+
+Example:
+	usbphy: phy at 0x01c13400 {
+		#phy-cells = <1>;
+		compatible = "allwinner,sun4i-a10-usb-phy";
+		reg = <0x01c13400 0x10 0x01c14800 0x4 0x01c1c800 0x4>;
+		clocks = <&usb_clk 8>;
+		clock-names = "usb_phy";
+		resets = <&usb_clk 1>, <&usb_clk 2>;
+		reset-names = "usb1_reset", "usb2_reset";
+	};
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 330ef2d..dcce4cf 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -51,4 +51,15 @@ config PHY_EXYNOS_DP_VIDEO
 	help
 	  Support for Display Port PHY found on Samsung EXYNOS SoCs.
 
+config PHY_SUN4I_USB
+	tristate "Allwinner sunxi SoC USB PHY driver"
+	depends on ARCH_SUNXI
+	select GENERIC_PHY
+	help
+	  Enable this to support the transceiver that is part of Allwinner
+	  sunxi SoCs.
+
+	  This driver controls the entire USB PHY block, both the USB OTG
+	  parts, as well as the 2 regular USB 2 host PHYs.
+
 endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index d0caae9..e9e82f0 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)	+= phy-exynos-dp-video.o
 obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
 obj-$(CONFIG_OMAP_USB2)			+= phy-omap-usb2.o
 obj-$(CONFIG_TWL4030_USB)		+= phy-twl4030-usb.o
+obj-$(CONFIG_PHY_SUN4I_USB)		+= phy-sun4i-usb.o
diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c
new file mode 100644
index 0000000..a15ecc1
--- /dev/null
+++ b/drivers/phy/phy-sun4i-usb.c
@@ -0,0 +1,318 @@
+/*
+ * Allwinner sun4i USB phy driver
+ *
+ * Copyright (C) 2014 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Based on code from
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ *
+ * Modelled after: Samsung S5P/EXYNOS SoC series MIPI CSIS/DSIM DPHY driver
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+
+#define REG_ISCR			0x00
+#define REG_PHYCTL			0x04
+#define REG_PHYBIST			0x08
+#define REG_PHYTUNE			0x0c
+
+#define SUNXI_AHB_ICHR8_EN		BIT(10)
+#define SUNXI_AHB_INCR4_BURST_EN	BIT(9)
+#define SUNXI_AHB_INCRX_ALIGN_EN	BIT(8)
+#define SUNXI_ULPI_BYPASS_EN		BIT(0)
+
+#define MAX_PHYS			3
+
+struct sun4i_usb_phy_data {
+	struct clk *clk;
+	void __iomem *base;
+	struct mutex mutex;
+	int num_phys;
+	u32 disc_thresh;
+	struct sun4i_usb_phy {
+		struct phy *phy;
+		void __iomem *pmu_irq;
+		struct regulator *vbus;
+		struct reset_control *reset;
+		int index;
+	} phys[MAX_PHYS];
+};
+
+#define to_sun4i_usb_phy_data(phy) \
+	container_of((phy), struct sun4i_usb_phy_data, phys[(phy)->index])
+
+static void sun4i_usb_phy_write(struct sun4i_usb_phy *phy, u32 addr, u32 data,
+				int len)
+{
+	struct sun4i_usb_phy_data *phy_data = to_sun4i_usb_phy_data(phy);
+	u32 temp, usbc_bit = BIT(phy->index * 2);
+	int i;
+
+	mutex_lock(&phy_data->mutex);
+
+	for (i = 0; i < len; i++) {
+		temp = readl(phy_data->base + REG_PHYCTL);
+
+		/* clear the address portion */
+		temp &= ~(0xff << 8);
+
+		/* set the address */
+		temp |= ((addr + i) << 8);
+		writel(temp, phy_data->base + REG_PHYCTL);
+
+		/* set the data bit and clear usbc bit*/
+		temp = readb(phy_data->base + REG_PHYCTL);
+		if (data & 0x1)
+			temp |= BIT(7);
+		else
+			temp &= ~BIT(7);
+		temp &= ~usbc_bit;
+		writeb(temp, phy_data->base + REG_PHYCTL);
+
+		/* pulse usbc_bit */
+		temp = readb(phy_data->base + REG_PHYCTL);
+		temp |= usbc_bit;
+		writeb(temp, phy_data->base + REG_PHYCTL);
+
+		temp = readb(phy_data->base + REG_PHYCTL);
+		temp &= ~usbc_bit;
+		writeb(temp, phy_data->base + REG_PHYCTL);
+
+		data >>= 1;
+	}
+	mutex_unlock(&phy_data->mutex);
+}
+
+static void sun4i_usb_phy_passby(struct sun4i_usb_phy *phy, int enable)
+{
+	u32 bits, reg_value;
+
+	if (!phy->pmu_irq)
+		return;
+
+	bits = SUNXI_AHB_ICHR8_EN | SUNXI_AHB_INCR4_BURST_EN |
+		SUNXI_AHB_INCRX_ALIGN_EN | SUNXI_ULPI_BYPASS_EN;
+
+	reg_value = readl(phy->pmu_irq);
+
+	if (enable)
+		reg_value |= bits;
+	else
+		reg_value &= ~bits;
+
+	writel(reg_value, phy->pmu_irq);
+}
+
+static int sun4i_usb_phy_init(struct phy *_phy)
+{
+	struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
+	struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy);
+	int ret;
+
+	ret = clk_prepare_enable(data->clk);
+	if (ret)
+		return ret;
+
+	ret = reset_control_deassert(phy->reset);
+	if (ret) {
+		clk_disable_unprepare(data->clk);
+		return ret;
+	}
+
+	/* Adjust PHY's magnitude and rate */
+	sun4i_usb_phy_write(phy, 0x20, 0x14, 5);
+
+	/* Disconnect threshold adjustment */
+	sun4i_usb_phy_write(phy, 0x2a, data->disc_thresh, 2);
+
+	sun4i_usb_phy_passby(phy, 1);
+
+	return 0;
+}
+
+static int sun4i_usb_phy_exit(struct phy *_phy)
+{
+	struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
+	struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy);
+
+	sun4i_usb_phy_passby(phy, 0);
+	reset_control_assert(phy->reset);
+	clk_disable_unprepare(data->clk);
+
+	return 0;
+}
+
+static int sun4i_usb_phy_power_on(struct phy *_phy)
+{
+	struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
+	int ret;
+
+	if (phy->vbus) {
+		ret = regulator_enable(phy->vbus);
+		if (ret)
+			return ret;
+
+	}
+
+	return 0;
+}
+
+static int sun4i_usb_phy_power_off(struct phy *_phy)
+{
+	struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
+
+	if (phy->vbus)
+		regulator_disable(phy->vbus);
+
+	return 0;
+}
+
+static struct phy_ops sun4i_usb_phy_ops = {
+	.init		= sun4i_usb_phy_init,
+	.exit		= sun4i_usb_phy_exit,
+	.power_on	= sun4i_usb_phy_power_on,
+	.power_off	= sun4i_usb_phy_power_off,
+	.owner		= THIS_MODULE,
+};
+
+static struct phy *sun4i_usb_phy_xlate(struct device *dev,
+					struct of_phandle_args *args)
+{
+	struct sun4i_usb_phy_data *data = dev_get_drvdata(dev);
+
+	if (WARN_ON(args->args[0] == 0 || args->args[0] >= data->num_phys))
+		return ERR_PTR(-ENODEV);
+
+	return data->phys[args->args[0]].phy;
+}
+
+static int sun4i_usb_phy_probe(struct platform_device *pdev)
+{
+	struct sun4i_usb_phy_data *data;
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	void __iomem *pmu_irq = NULL;
+	struct phy_provider *phy_provider;
+	struct reset_control *reset;
+	struct regulator *vbus;
+	struct phy *phy;
+	char name[16];
+	int i;
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	mutex_init(&data->mutex);
+	if (of_device_is_compatible(np, "allwinner,sun4i-a10-usb-phy")) {
+		data->num_phys = 3;
+		data->disc_thresh = 3;
+	} else if (of_device_is_compatible(np,
+					"allwinner,sun5i-a13-usb-phy")) {
+		data->num_phys = 2;
+		data->disc_thresh = 2;
+	} else { /* allwinner,sun7i-a20-usb-phy */
+		data->num_phys = 3;
+		data->disc_thresh = 2;
+	}
+
+	data->clk = devm_clk_get(dev, "usb_phy");
+	if (IS_ERR(data->clk)) {
+		dev_err(dev, "could not get usb_phy clock\n");
+		return PTR_ERR(data->clk);
+	}
+
+	/* Skip 0, 0 is the phy for otg which is not yet supported. */
+	for (i = 1; i < data->num_phys; i++) {
+		snprintf(name, sizeof(name), "usb%d_vbus", i);
+		vbus = devm_regulator_get_optional(dev, name);
+		if (IS_ERR(vbus)) {
+			if (PTR_ERR(vbus) == -EPROBE_DEFER)
+				return -EPROBE_DEFER;
+			vbus = NULL;
+		}
+
+		snprintf(name, sizeof(name), "usb%d_reset", i);
+		reset = devm_reset_control_get(dev, name);
+		if (IS_ERR(phy)) {
+			dev_err(dev, "failed to get reset %s\n", name);
+			return PTR_ERR(phy);
+		}
+
+		if (i) { /* No pmu_irq for usbc0 */
+			pmu_irq = devm_ioremap_resource(dev,
+			      platform_get_resource(pdev, IORESOURCE_MEM, i));
+			if (IS_ERR(pmu_irq))
+				return PTR_ERR(pmu_irq);
+		}
+
+		phy = devm_phy_create(dev, &sun4i_usb_phy_ops, NULL);
+		if (IS_ERR(phy)) {
+			dev_err(dev, "failed to create PHY %d\n", i);
+			return PTR_ERR(phy);
+		}
+
+		data->phys[i].phy = phy;
+		data->phys[i].pmu_irq = pmu_irq;
+		data->phys[i].vbus = vbus;
+		data->phys[i].reset = reset;
+		data->phys[i].index = i;
+		phy_set_drvdata(phy, &data->phys[i]);
+	}
+
+	data->base = devm_ioremap_resource(dev,
+			platform_get_resource(pdev, IORESOURCE_MEM, 0));
+	if (IS_ERR(data->base))
+		return PTR_ERR(data->base);
+
+	dev_set_drvdata(dev, data);
+	phy_provider = devm_of_phy_provider_register(dev, sun4i_usb_phy_xlate);
+	if (IS_ERR(phy_provider))
+		return PTR_ERR(phy_provider);
+
+	return 0;
+}
+
+static const struct of_device_id sun4i_usb_phy_of_match[] = {
+	{ .compatible = "allwinner,sun4i-a10-usb-phy" },
+	{ .compatible = "allwinner,sun5i-a13-usb-phy" },
+	{ .compatible = "allwinner,sun7i-a20-usb-phy" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match);
+
+static struct platform_driver sun4i_usb_phy_driver = {
+	.probe	= sun4i_usb_phy_probe,
+	.driver = {
+		.of_match_table	= sun4i_usb_phy_of_match,
+		.name  = "sun4i-usb-phy",
+		.owner = THIS_MODULE,
+	}
+};
+module_platform_driver(sun4i_usb_phy_driver);
+
+MODULE_DESCRIPTION("Allwinner sun4i USB phy driver");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_LICENSE("GPL");
-- 
1.8.4.2

^ 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