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.
v5:
- rebased to v3.13 tag
- make UART DT node a child of 'rdb' node
- fix ordering of debug UART entries
v4:
- make a reboot driver and put it in the drivers folder
- rework DT bindings to leverage 'syscon'
- rework BSP code to use 'syscon' for all register mappings
- misc. tweaks per suggestions from v3
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 (8):
ARM: brcmstb: add infrastructure for ARM-based Broadcom STB SoCs
power: reset: Add reboot driver for brcmstb
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 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 | 95 ++++++
Documentation/devicetree/bindings/arm/cpus.txt | 1 +
Documentation/devicetree/bindings/arm/gic.txt | 1 +
arch/arm/Kconfig.debug | 16 +-
arch/arm/boot/dts/bcm7445.dts | 111 +++++++
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 | 110 +++++++
arch/arm/mach-bcm/brcmstb.h | 38 +++
arch/arm/mach-bcm/headsmp-brcmstb.S | 34 ++
arch/arm/mach-bcm/hotplug-brcmstb.c | 334 ++++++++++++++++++++
arch/arm/mm/proc-v7.S | 11 +
drivers/power/reset/Kconfig | 10 +
drivers/power/reset/Makefile | 1 +
drivers/power/reset/brcmstb-reboot.c | 120 +++++++
16 files changed, 900 insertions(+), 1 deletions(-)
create mode 100644 Documentation/devicetree/bindings/arm/brcm-brcmstb.txt
create mode 100644 arch/arm/boot/dts/bcm7445.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
create mode 100644 drivers/power/reset/brcmstb-reboot.c
Add the UART definitions needed to support earlyprintk on brcmstb machines.
Signed-off-by: Marc Carino <[email protected]>
Acked-by: Florian Fainelli <[email protected]>
---
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..666afd7 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
@@ -1008,6 +1019,7 @@ config DEBUG_UART_PHYS
default 0xd4018000 if DEBUG_MMP_UART3
default 0xe0000000 if ARCH_SPEAR13XX
default 0xf0000be0 if ARCH_EBSA110
+ default 0xf0406b00 if DEBUG_BRCMSTB_UART
default 0xf1012000 if DEBUG_MVEBU_UART_ALTERNATE
default 0xf1012000 if ARCH_DOVE || ARCH_KIRKWOOD || ARCH_MV78XX0 || \
ARCH_ORION5X
@@ -1040,6 +1052,7 @@ config DEBUG_UART_VIRT
default 0xf8090000 if DEBUG_VEXPRESS_UART0_RS1
default 0xfb009000 if DEBUG_REALVIEW_STD_PORT
default 0xfb10c000 if DEBUG_REALVIEW_PB1176_PORT
+ default 0xfc406b00 if DEBUG_BRCMSTB_UART
default 0xfd000000 if ARCH_SPEAR3XX || ARCH_SPEAR6XX
default 0xfd000000 if ARCH_SPEAR13XX
default 0xfd012000 if ARCH_MV78XX0
@@ -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
Document the Broadcom Brahma B15 GIC implementation as compatible
with the ARM GIC standard.
Signed-off-by: Marc Carino <[email protected]>
Acked-by: Florian Fainelli <[email protected]>
---
Documentation/devicetree/bindings/arm/gic.txt | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/Documentation/devicetree/bindings/arm/gic.txt b/Documentation/devicetree/bindings/arm/gic.txt
index 3dfb0c0..d7409fd 100644
--- a/Documentation/devicetree/bindings/arm/gic.txt
+++ b/Documentation/devicetree/bindings/arm/gic.txt
@@ -15,6 +15,7 @@ Main node required properties:
"arm,cortex-a9-gic"
"arm,cortex-a7-gic"
"arm,arm11mp-gic"
+ "brcm,brahma-b15-gic"
- interrupt-controller : Identifies the node as an interrupt controller
- #interrupt-cells : Specifies the number of cells needed to encode an
interrupt source. The type shall be a <u32> and the value shall be 3.
--
1.7.1
Document the bindings that the Broadcom STB platform needs
for proper bootup.
Signed-off-by: Marc Carino <[email protected]>
Acked-by: Florian Fainelli <[email protected]>
---
.../devicetree/bindings/arm/brcm-brcmstb.txt | 95 ++++++++++++++++++++
1 files changed, 95 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..3c436cc
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/brcm-brcmstb.txt
@@ -0,0 +1,95 @@
+ARM Broadcom STB platforms Device Tree Bindings
+-----------------------------------------------
+Boards with Broadcom Brahma15 ARM-based BCMxxxx (generally BCM7xxx variants)
+SoC shall have the following DT organization:
+
+Required root node properties:
+ - compatible: "brcm,bcm<chip_id>", "brcm,brcmstb"
+
+example:
+/ {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ model = "Broadcom STB (bcm7445)";
+ compatible = "brcm,bcm7445", "brcm,brcmstb";
+
+Further, syscon nodes that map platform-specific registers used for general
+system control is required:
+
+ - compatible: "brcm,bcm<chip_id>-sun-top-ctrl", "syscon"
+ - compatible: "brcm,bcm<chip_id>-hif-cpubiuctrl", "syscon"
+ - compatible: "brcm,bcm<chip_id>-hif-continuation", "syscon"
+
+example:
+ rdb {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges = <0 0x00 0xf0000000 0x1000000>;
+
+ sun_top_ctrl: syscon@404000 {
+ compatible = "brcm,bcm7445-sun-top-ctrl", "syscon";
+ reg = <0x404000 0x51c>;
+ };
+
+ hif_cpubiuctrl: syscon@3e2400 {
+ compatible = "brcm,bcm7445-hif-cpubiuctrl", "syscon";
+ reg = <0x3e2400 0x5b4>;
+ };
+
+ hif_continuation: syscon@452000 {
+ compatible = "brcm,bcm7445-hif-continuation", "syscon";
+ reg = <0x452000 0x100>;
+ };
+ };
+
+Lastly, nodes that allow for support of SMP initialization and reboot are
+required:
+
+smpboot
+-------
+Required properties:
+
+ - compatible
+ The string "brcm,brcmstb-smpboot".
+
+ - syscon-cpu
+ A phandle / integer array property which lets the BSP know the location
+ of certain CPU power-on registers.
+
+ The layout of the property is as follows:
+ o a phandle to the "hif_cpubiuctrl" syscon node
+ o offset to the base CPU power zone register
+ o offset to the base CPU reset register
+
+ - syscon-cont
+ A phandle pointing to the syscon node which describes the CPU boot
+ continuation registers.
+ o a phandle to the "hif_continuation" syscon node
+
+example:
+ smpboot {
+ compatible = "brcm,brcmstb-smpboot";
+ syscon-cpu = <&hif_cpubiuctrl 0x88 0x178>;
+ syscon-cont = <&hif_continuation>;
+ };
+
+reboot
+-------
+Required properties
+
+ - compatible
+ The string property "brcm,brcmstb-reboot".
+
+ - syscon
+ A phandle / integer array that points to the syscon node which describes
+ the general system reset registers.
+ o a phandle to "sun_top_ctrl"
+ o offset to the "reset source enable" register
+ o offset to the "software master reset" register
+
+example:
+ reboot {
+ compatible = "brcm,brcmstb-reboot";
+ syscon = <&sun_top_ctrl 0x304 0x308>;
+ };
--
1.7.1
Add the Broadcom Brahma B15 CPU to the DT CPU binding list.
Signed-off-by: Marc Carino <[email protected]>
Acked-by: Florian Fainelli <[email protected]>
---
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..0cd1e25 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,brahma-b15"
"faraday,fa526"
"intel,sa110"
"intel,sa1100"
--
1.7.1
Perform any CPU-specific initialization required on the
Broadcom Brahma-15 core.
Signed-off-by: Marc Carino <[email protected]>
Acked-by: Florian Fainelli <[email protected]>
---
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
Add support for reboot functionality on boards with ARM-based
Broadcom STB chipsets.
Signed-off-by: Marc Carino <[email protected]>
---
drivers/power/reset/Kconfig | 10 +++
drivers/power/reset/Makefile | 1 +
drivers/power/reset/brcmstb-reboot.c | 120 ++++++++++++++++++++++++++++++++++
3 files changed, 131 insertions(+), 0 deletions(-)
create mode 100644 drivers/power/reset/brcmstb-reboot.c
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index 9b3ea53..31b468b 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -6,6 +6,16 @@ menuconfig POWER_RESET
Say Y here to enable board reset and power off
+config POWER_RESET_BRCMSTB
+ bool "Broadcom STB reset driver"
+ depends on POWER_RESET && ARCH_BRCMSTB
+ help
+ This driver provides restart support for ARM-based Broadcom STB
+ boards.
+
+ Say Y here if you have an ARM-based Broadcom STB board and you wish
+ to have restart support.
+
config POWER_RESET_GPIO
bool "GPIO power-off driver"
depends on OF_GPIO && POWER_RESET
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index 3e6ed88..806d056 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -4,3 +4,4 @@ obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o
obj-$(CONFIG_POWER_RESET_VEXPRESS) += vexpress-poweroff.o
obj-$(CONFIG_POWER_RESET_XGENE) += xgene-reboot.o
+obj-$(CONFIG_POWER_RESET_BRCMSTB) += brcmstb-reboot.o
diff --git a/drivers/power/reset/brcmstb-reboot.c b/drivers/power/reset/brcmstb-reboot.c
new file mode 100644
index 0000000..3f23692
--- /dev/null
+++ b/drivers/power/reset/brcmstb-reboot.c
@@ -0,0 +1,120 @@
+/*
+ * 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/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/reboot.h>
+#include <linux/regmap.h>
+#include <linux/smp.h>
+#include <linux/mfd/syscon.h>
+
+#include <asm/system_misc.h>
+
+#define RESET_SOURCE_ENABLE_REG 1
+#define SW_MASTER_RESET_REG 2
+
+static struct regmap *regmap;
+static u32 rst_src_en;
+static u32 sw_mstr_rst;
+
+static void brcmstb_reboot(enum reboot_mode mode, const char *cmd)
+{
+ int rc;
+ u32 tmp;
+
+ rc = regmap_write(regmap, rst_src_en, 1);
+ if (rc) {
+ pr_err("failed to write rst_src_en (%d)\n", rc);
+ return;
+ }
+
+ rc = regmap_read(regmap, rst_src_en, &tmp);
+ if (rc) {
+ pr_err("failed to read rst_src_en (%d)\n", rc);
+ return;
+ }
+
+ rc = regmap_write(regmap, sw_mstr_rst, 1);
+ if (rc) {
+ pr_err("failed to write sw_mstr_rst (%d)\n", rc);
+ return;
+ }
+
+ rc = regmap_read(regmap, sw_mstr_rst, &tmp);
+ if (rc) {
+ pr_err("failed to read sw_mstr_rst (%d)\n", rc);
+ return;
+ }
+
+ while (1)
+ ;
+}
+
+static int brcmstb_reboot_probe(struct platform_device *pdev)
+{
+ int rc;
+ struct device_node *np = pdev->dev.of_node;
+
+ regmap = syscon_regmap_lookup_by_phandle(np, "syscon");
+ if (IS_ERR(regmap)) {
+ pr_err("failed to get syscon phandle\n");
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32_index(np, "syscon", RESET_SOURCE_ENABLE_REG,
+ &rst_src_en);
+ if (rc) {
+ pr_err("can't get rst_src_en offset (%d)\n", rc);
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32_index(np, "syscon", SW_MASTER_RESET_REG,
+ &sw_mstr_rst);
+ if (rc) {
+ pr_err("can't get sw_mstr_rst offset (%d)\n", rc);
+ return -EINVAL;
+ }
+
+ arm_pm_restart = brcmstb_reboot;
+
+ return 0;
+}
+
+static const struct of_device_id of_match[] = {
+ { .compatible = "brcm,brcmstb-reboot", },
+ {},
+};
+
+static struct platform_driver brcmstb_reboot_driver = {
+ .probe = brcmstb_reboot_probe,
+ .driver = {
+ .name = "brcmstb-reboot",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match,
+ },
+};
+
+static int __init brcmstb_reboot_init(void)
+{
+ return platform_driver_probe(&brcmstb_reboot_driver,
+ brcmstb_reboot_probe);
+}
+subsys_initcall(brcmstb_reboot_init);
--
1.7.1
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 <[email protected]>
Acked-by: Florian Fainelli <[email protected]>
---
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 | 110 ++++++++++++
arch/arm/mach-bcm/brcmstb.h | 38 ++++
arch/arm/mach-bcm/headsmp-brcmstb.S | 34 ++++
arch/arm/mach-bcm/hotplug-brcmstb.c | 334 +++++++++++++++++++++++++++++++++++
7 files changed, 535 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..7a6093d
--- /dev/null
+++ b/arch/arm/mach-bcm/brcmstb.c
@@ -0,0 +1,110 @@
+/*
+ * 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,bcm7445",
+ "brcm,brcmstb",
+ NULL
+};
+
+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,
+#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..e49bde6
--- /dev/null
+++ b/arch/arm/mach-bcm/brcmstb.h
@@ -0,0 +1,38 @@
+/*
+ * 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;
+#if defined(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
+
+#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..ff4a732
--- /dev/null
+++ b/arch/arm/mach-bcm/hotplug-brcmstb.c
@@ -0,0 +1,334 @@
+/*
+ * 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/regmap.h>
+#include <linux/smp.h>
+#include <linux/mfd/syscon.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 *cpubiuctrl_block;
+static void __iomem *hif_cont_block;
+static u32 cpu0_pwr_zone_ctrl_reg;
+static u32 cpu_rst_cfg_reg;
+static u32 hif_cont_reg;
+DEFINE_PER_CPU(int, per_cpu_sw_state);
+
+static void __iomem *pwr_ctrl_get_base(unsigned int cpu)
+{
+ void __iomem *base = cpubiuctrl_block + 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);
+}
+
+static void cpu_rst_cfg_set(int cpu, int set)
+{
+ u32 val;
+ val = readl_relaxed(cpubiuctrl_block + cpu_rst_cfg_reg);
+ if (set)
+ val |= BIT(cpu);
+ else
+ val &= ~BIT(cpu);
+ writel_relaxed(val, cpubiuctrl_block + cpu_rst_cfg_reg);
+}
+
+static void cpu_set_boot_addr(int cpu, unsigned long boot_addr)
+{
+ const int reg_ofs = cpu * 8;
+ writel_relaxed(0, hif_cont_block + hif_cont_reg + reg_ofs);
+ writel_relaxed(boot_addr, hif_cont_block + hif_cont_reg + 4 + reg_ofs);
+}
+
+void brcmstb_cpu_boot(unsigned int cpu)
+{
+ pr_info("SMP: Booting CPU%d...\n", cpu);
+
+ /*
+ * set the reset vector to point to the secondary_startup
+ * routine
+ */
+ cpu_set_boot_addr(cpu, virt_to_phys(brcmstb_secondary_startup));
+
+ flush_cache_all();
+
+ /* unhalt the cpu */
+ cpu_rst_cfg_set(cpu, 0);
+}
+
+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;
+
+ 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 */
+ cpu_rst_cfg_set(cpu, 1);
+
+ return 1;
+}
+
+static int __init setup_hifcpubiuctrl_regs(struct device_node *np)
+{
+ int rc = 0;
+ char *name;
+ int index;
+ struct device_node *syscon_np = NULL;
+
+ name = "syscon-cpu";
+
+ syscon_np = of_parse_phandle(np, name, 0);
+ if (!syscon_np) {
+ pr_err("can't find phandle %s\n", name);
+ rc = -EINVAL;
+ goto cleanup;
+ }
+
+ cpubiuctrl_block = of_iomap(syscon_np, 0);
+ if (!cpubiuctrl_block) {
+ pr_err("iomap failed for cpubiuctrl_block\n");
+ rc = -EINVAL;
+ goto cleanup;
+ }
+
+ index = 1;
+ rc = of_property_read_u32_index(np, name, index,
+ &cpu0_pwr_zone_ctrl_reg);
+ if (rc) {
+ pr_err("failed to read %d from %s property (%d)\n", index, name,
+ rc);
+ rc = -EINVAL;
+ goto cleanup;
+ }
+
+ index = 2;
+ rc = of_property_read_u32_index(np, name, index, &cpu_rst_cfg_reg);
+ if (rc) {
+ pr_err("failed to read %d from %s property (%d)\n", index, name,
+ rc);
+ rc = -EINVAL;
+ goto cleanup;
+ }
+
+cleanup:
+ if (syscon_np)
+ of_node_put(syscon_np);
+
+ return rc;
+}
+
+static int __init setup_hifcont_regs(struct device_node *np)
+{
+ int rc = 0;
+ char *name;
+ struct device_node *syscon_np = NULL;
+
+ name = "syscon-cont";
+
+ syscon_np = of_parse_phandle(np, name, 0);
+ if (!syscon_np) {
+ pr_err("can't find phandle %s\n", name);
+ rc = -EINVAL;
+ goto cleanup;
+ }
+
+ hif_cont_block = of_iomap(syscon_np, 0);
+ if (!hif_cont_block) {
+ pr_err("iomap failed for hif_cont_block\n");
+ rc = -EINVAL;
+ goto cleanup;
+ }
+
+ /* offset is at top of hif_cont_block */
+ hif_cont_reg = 0;
+
+cleanup:
+ if (syscon_np)
+ of_node_put(syscon_np);
+
+ return rc;
+}
+
+void __init brcmstb_cpu_ctrl_setup(unsigned int max_cpus)
+{
+ int rc;
+ struct device_node *np;
+ char *name;
+
+ name = "brcm,brcmstb-smpboot";
+ np = of_find_compatible_node(NULL, NULL, name);
+ if (!np) {
+ pr_err("can't find compatible node %s\n", name);
+ return;
+ }
+
+ rc = setup_hifcpubiuctrl_regs(np);
+ if (rc)
+ return;
+
+ rc = setup_hifcont_regs(np);
+ if (rc)
+ return;
+}
+
--
1.7.1
Add a sample DTS which will allow bootup of a board populated
with the BCM7445 chip.
Signed-off-by: Marc Carino <[email protected]>
Acked-by: Florian Fainelli <[email protected]>
---
arch/arm/boot/dts/bcm7445.dts | 111 +++++++++++++++++++++++++++++++++++++++++
1 files changed, 111 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/boot/dts/bcm7445.dts
diff --git a/arch/arm/boot/dts/bcm7445.dts b/arch/arm/boot/dts/bcm7445.dts
new file mode 100644
index 0000000..ffa3305
--- /dev/null
+++ b/arch/arm/boot/dts/bcm7445.dts
@@ -0,0 +1,111 @@
+/dts-v1/;
+/include/ "skeleton.dtsi"
+
+/ {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ model = "Broadcom STB (bcm7445)";
+ compatible = "brcm,bcm7445", "brcm,brcmstb";
+ interrupt-parent = <&gic>;
+
+ chosen {};
+
+ memory {
+ device_type = "memory";
+ reg = <0x00 0x00000000 0x00 0x40000000>,
+ <0x00 0x40000000 0x00 0x40000000>,
+ <0x00 0x80000000 0x00 0x40000000>;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ compatible = "brcm,brahma-b15";
+ device_type = "cpu";
+ reg = <0>;
+ };
+
+ cpu@1 {
+ compatible = "brcm,brahma-b15";
+ device_type = "cpu";
+ reg = <1>;
+ };
+
+ cpu@2 {
+ compatible = "brcm,brahma-b15";
+ device_type = "cpu";
+ reg = <2>;
+ };
+
+ cpu@3 {
+ compatible = "brcm,brahma-b15";
+ device_type = "cpu";
+ reg = <3>;
+ };
+ };
+
+ gic: interrupt-controller@ffd00000 {
+ compatible = "brcm,brahma-b15-gic", "arm,cortex-a15-gic";
+ reg = <0x00 0xffd01000 0x00 0x1000>,
+ <0x00 0xffd02000 0x00 0x2000>,
+ <0x00 0xffd04000 0x00 0x2000>,
+ <0x00 0xffd06000 0x00 0x2000>;
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ };
+
+ timer {
+ compatible = "arm,armv7-timer";
+ interrupts = <1 13 0xf08>,
+ <1 14 0xf08>,
+ <1 11 0xf08>,
+ <1 10 0xf08>;
+ };
+
+ rdb {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges = <0 0x00 0xf0000000 0x1000000>;
+
+ serial@406b00 {
+ compatible = "ns16550a";
+ reg = <0x406b00 0x20>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ interrupts = <0 75 0x4>;
+ clock-frequency = <0x4d3f640>;
+ };
+
+ sun_top_ctrl: syscon@404000 {
+ compatible = "brcm,bcm7445-sun-top-ctrl",
+ "syscon";
+ reg = <0x404000 0x51c>;
+ };
+
+ hif_cpubiuctrl: syscon@3e2400 {
+ compatible = "brcm,bcm7445-hif-cpubiuctrl",
+ "syscon";
+ reg = <0x3e2400 0x5b4>;
+ };
+
+ hif_continuation: syscon@452000 {
+ compatible = "brcm,bcm7445-hif-continuation",
+ "syscon";
+ reg = <0x452000 0x100>;
+ };
+ };
+
+ smpboot {
+ compatible = "brcm,brcmstb-smpboot";
+ syscon-cpu = <&hif_cpubiuctrl 0x88 0x178>;
+ syscon-cont = <&hif_continuation>;
+ };
+
+ reboot {
+ compatible = "brcm,brcmstb-reboot";
+ syscon = <&sun_top_ctrl 0x304 0x308>;
+ };
+};
--
1.7.1
Hi Marc,
2014/1/21 Marc Carino <[email protected]>:
> Document the Broadcom Brahma B15 GIC implementation as compatible
> with the ARM GIC standard.
>
> Signed-off-by: Marc Carino <[email protected]>
> Acked-by: Florian Fainelli <[email protected]>
Do not we also need to update drivers/irqchip/irq-gic.c to look for
this compatible property? Alternatively should the example DTS contain
the following:
compatible = "brcm,brahma-b15-gic", "arm,cortex-a15-gic"?
> ---
> Documentation/devicetree/bindings/arm/gic.txt | 1 +
> 1 files changed, 1 insertions(+), 0 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/arm/gic.txt b/Documentation/devicetree/bindings/arm/gic.txt
> index 3dfb0c0..d7409fd 100644
> --- a/Documentation/devicetree/bindings/arm/gic.txt
> +++ b/Documentation/devicetree/bindings/arm/gic.txt
> @@ -15,6 +15,7 @@ Main node required properties:
> "arm,cortex-a9-gic"
> "arm,cortex-a7-gic"
> "arm,arm11mp-gic"
> + "brcm,brahma-b15-gic"
> - interrupt-controller : Identifies the node as an interrupt controller
> - #interrupt-cells : Specifies the number of cells needed to encode an
> interrupt source. The type shall be a <u32> and the value shall be 3.
> --
> 1.7.1
>
--
Florian
Hi Florian,
> Do not we also need to update drivers/irqchip/irq-gic.c to look for
> this compatible property? Alternatively should the example DTS contain
> the following:
>
> compatible = "brcm,brahma-b15-gic", "arm,cortex-a15-gic"?
Patch #8 [1] of this series has the "compatible" string set exactly that way. I was
following the pattern seen in the other reference DTS files, where "arm,cortex-a15-gic" is
used as the fall-back.
Thanks,
Marc C
[1] https://lkml.org/lkml/2014/1/21/649
On 01/22/2014 02:40 PM, Florian Fainelli wrote:
> Hi Marc,
>
> 2014/1/21 Marc Carino <[email protected]>:
>> Document the Broadcom Brahma B15 GIC implementation as compatible
>> with the ARM GIC standard.
>>
>> Signed-off-by: Marc Carino <[email protected]>
>> Acked-by: Florian Fainelli <[email protected]>
>
> Do not we also need to update drivers/irqchip/irq-gic.c to look for
> this compatible property? Alternatively should the example DTS contain
> the following:
>
> compatible = "brcm,brahma-b15-gic", "arm,cortex-a15-gic"?
>
>> ---
>> Documentation/devicetree/bindings/arm/gic.txt | 1 +
>> 1 files changed, 1 insertions(+), 0 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/arm/gic.txt b/Documentation/devicetree/bindings/arm/gic.txt
>> index 3dfb0c0..d7409fd 100644
>> --- a/Documentation/devicetree/bindings/arm/gic.txt
>> +++ b/Documentation/devicetree/bindings/arm/gic.txt
>> @@ -15,6 +15,7 @@ Main node required properties:
>> "arm,cortex-a9-gic"
>> "arm,cortex-a7-gic"
>> "arm,arm11mp-gic"
>> + "brcm,brahma-b15-gic"
>> - interrupt-controller : Identifies the node as an interrupt controller
>> - #interrupt-cells : Specifies the number of cells needed to encode an
>> interrupt source. The type shall be a <u32> and the value shall be 3.
>> --
>> 1.7.1
>>
>
>
>
Hi Marc,
2014/1/22 Marc C <[email protected]>:
> Hi Florian,
>
>> Do not we also need to update drivers/irqchip/irq-gic.c to look for
>> this compatible property? Alternatively should the example DTS contain
>> the following:
>>
>> compatible = "brcm,brahma-b15-gic", "arm,cortex-a15-gic"?
>
> Patch #8 [1] of this series has the "compatible" string set exactly that way. I was
> following the pattern seen in the other reference DTS files, where "arm,cortex-a15-gic" is
> used as the fall-back.
Ah, I missed that, thanks! How about the CPU compatible property?
AFAIK it is only used by arch/arm/kernel/topology.c, I am not sure if
we have the exact same number to use as the "vanilla" Cortex-A15 here,
or if we should have another number match against "brcm,brahma-b15".
What do you think?
>
> Thanks,
> Marc C
>
> [1] https://lkml.org/lkml/2014/1/21/649
>
> On 01/22/2014 02:40 PM, Florian Fainelli wrote:
>> Hi Marc,
>>
>> 2014/1/21 Marc Carino <[email protected]>:
>>> Document the Broadcom Brahma B15 GIC implementation as compatible
>>> with the ARM GIC standard.
>>>
>>> Signed-off-by: Marc Carino <[email protected]>
>>> Acked-by: Florian Fainelli <[email protected]>
>>
>> Do not we also need to update drivers/irqchip/irq-gic.c to look for
>> this compatible property? Alternatively should the example DTS contain
>> the following:
>>
>> compatible = "brcm,brahma-b15-gic", "arm,cortex-a15-gic"?
>>
>>> ---
>>> Documentation/devicetree/bindings/arm/gic.txt | 1 +
>>> 1 files changed, 1 insertions(+), 0 deletions(-)
>>>
>>> diff --git a/Documentation/devicetree/bindings/arm/gic.txt b/Documentation/devicetree/bindings/arm/gic.txt
>>> index 3dfb0c0..d7409fd 100644
>>> --- a/Documentation/devicetree/bindings/arm/gic.txt
>>> +++ b/Documentation/devicetree/bindings/arm/gic.txt
>>> @@ -15,6 +15,7 @@ Main node required properties:
>>> "arm,cortex-a9-gic"
>>> "arm,cortex-a7-gic"
>>> "arm,arm11mp-gic"
>>> + "brcm,brahma-b15-gic"
>>> - interrupt-controller : Identifies the node as an interrupt controller
>>> - #interrupt-cells : Specifies the number of cells needed to encode an
>>> interrupt source. The type shall be a <u32> and the value shall be 3.
>>> --
>>> 1.7.1
>>>
>>
>>
>>
>
>
>
--
Florian
Hi Florian,
>> Patch #8 [1] of this series has the "compatible" string set exactly that way. I was
>> following the pattern seen in the other reference DTS files, where "arm,cortex-a15-gic" is
>> used as the fall-back.
>
> Ah, I missed that, thanks! How about the CPU compatible property?
> AFAIK it is only used by arch/arm/kernel/topology.c, I am not sure if
> we have the exact same number to use as the "vanilla" Cortex-A15 here,
> or if we should have another number match against "brcm,brahma-b15".
> What do you think?
I think we should let the code fall-through to use the "SCHED_POWER_SCALE" defaults for
now, and not have an entry in the efficiency table. There are currently no BCM7xxx
platforms architected with heterogeneous multi-processing or multiple disparate CPU
clusters (like big.LITTLE).
Thanks,
Marc
On 01/23/2014 10:26 AM, Florian Fainelli wrote:
> Hi Marc,
>
> 2014/1/22 Marc C <[email protected]>:
>> Hi Florian,
>>
>>> Do not we also need to update drivers/irqchip/irq-gic.c to look for
>>> this compatible property? Alternatively should the example DTS contain
>>> the following:
>>>
>>> compatible = "brcm,brahma-b15-gic", "arm,cortex-a15-gic"?
>>
>> Patch #8 [1] of this series has the "compatible" string set exactly that way. I was
>> following the pattern seen in the other reference DTS files, where "arm,cortex-a15-gic" is
>> used as the fall-back.
>
> Ah, I missed that, thanks! How about the CPU compatible property?
> AFAIK it is only used by arch/arm/kernel/topology.c, I am not sure if
> we have the exact same number to use as the "vanilla" Cortex-A15 here,
> or if we should have another number match against "brcm,brahma-b15".
> What do you think?
>
>>
>> Thanks,
>> Marc C
>>
>> [1] https://lkml.org/lkml/2014/1/21/649
>>
>> On 01/22/2014 02:40 PM, Florian Fainelli wrote:
>>> Hi Marc,
>>>
>>> 2014/1/21 Marc Carino <[email protected]>:
>>>> Document the Broadcom Brahma B15 GIC implementation as compatible
>>>> with the ARM GIC standard.
>>>>
>>>> Signed-off-by: Marc Carino <[email protected]>
>>>> Acked-by: Florian Fainelli <[email protected]>
>>>
>>> Do not we also need to update drivers/irqchip/irq-gic.c to look for
>>> this compatible property? Alternatively should the example DTS contain
>>> the following:
>>>
>>> compatible = "brcm,brahma-b15-gic", "arm,cortex-a15-gic"?
>>>
>>>> ---
>>>> Documentation/devicetree/bindings/arm/gic.txt | 1 +
>>>> 1 files changed, 1 insertions(+), 0 deletions(-)
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/arm/gic.txt b/Documentation/devicetree/bindings/arm/gic.txt
>>>> index 3dfb0c0..d7409fd 100644
>>>> --- a/Documentation/devicetree/bindings/arm/gic.txt
>>>> +++ b/Documentation/devicetree/bindings/arm/gic.txt
>>>> @@ -15,6 +15,7 @@ Main node required properties:
>>>> "arm,cortex-a9-gic"
>>>> "arm,cortex-a7-gic"
>>>> "arm,arm11mp-gic"
>>>> + "brcm,brahma-b15-gic"
>>>> - interrupt-controller : Identifies the node as an interrupt controller
>>>> - #interrupt-cells : Specifies the number of cells needed to encode an
>>>> interrupt source. The type shall be a <u32> and the value shall be 3.
>>>> --
>>>> 1.7.1
>>>>
>>>
>>>
>>>
>>
>>
>>
>
>
>
On Wed, Jan 22, 2014 at 03:30:45AM +0000, Marc Carino wrote:
> 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 <[email protected]>
> Acked-by: Florian Fainelli <[email protected]>
> ---
> 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 | 110 ++++++++++++
> arch/arm/mach-bcm/brcmstb.h | 38 ++++
> arch/arm/mach-bcm/headsmp-brcmstb.S | 34 ++++
> arch/arm/mach-bcm/hotplug-brcmstb.c | 334 +++++++++++++++++++++++++++++++++++
> 7 files changed, 535 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..7a6093d
> --- /dev/null
> +++ b/arch/arm/mach-bcm/brcmstb.c
> @@ -0,0 +1,110 @@
> +/*
> + * 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,bcm7445",
> + "brcm,brcmstb",
> + NULL
> +};
> +
> +static void __init brcmstb_init_early(void)
> +{
> + add_preferred_console("ttyS", 0, "115200");
> +}
Is this really required?
> +
> +/***********************************************************************
> + * 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,
> +#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..e49bde6
> --- /dev/null
> +++ b/arch/arm/mach-bcm/brcmstb.h
> @@ -0,0 +1,38 @@
> +/*
> + * 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;
> +#if defined(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
> +
> +#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
__CPUINIT is either going or gone by now. This should disappear.
> +
> +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..ff4a732
> --- /dev/null
> +++ b/arch/arm/mach-bcm/hotplug-brcmstb.c
> @@ -0,0 +1,334 @@
> +/*
> + * 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/regmap.h>
> +#include <linux/smp.h>
> +#include <linux/mfd/syscon.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 *cpubiuctrl_block;
> +static void __iomem *hif_cont_block;
> +static u32 cpu0_pwr_zone_ctrl_reg;
> +static u32 cpu_rst_cfg_reg;
> +static u32 hif_cont_reg;
> +DEFINE_PER_CPU(int, per_cpu_sw_state);
> +
> +static void __iomem *pwr_ctrl_get_base(unsigned int cpu)
> +{
> + void __iomem *base = cpubiuctrl_block + cpu0_pwr_zone_ctrl_reg;
> + base += (cpu * 4);
CPU isn't guaranteed to be the physical CPU ID (MPIDR.Aff*). While it
almost certainly will be, we can't guarantee it in the face of a kexec,
for example.
You can use cpu_logical_map(cpu) to get the physical ID.
> + 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);
> +}
> +
> +static void cpu_rst_cfg_set(int cpu, int set)
> +{
> + u32 val;
> + val = readl_relaxed(cpubiuctrl_block + cpu_rst_cfg_reg);
> + if (set)
> + val |= BIT(cpu);
> + else
> + val &= ~BIT(cpu);
Likewise here.
> + writel_relaxed(val, cpubiuctrl_block + cpu_rst_cfg_reg);
> +}
> +
> +static void cpu_set_boot_addr(int cpu, unsigned long boot_addr)
> +{
> + const int reg_ofs = cpu * 8;
And here.
> + writel_relaxed(0, hif_cont_block + hif_cont_reg + reg_ofs);
> + writel_relaxed(boot_addr, hif_cont_block + hif_cont_reg + 4 + reg_ofs);
> +}
> +
> +void brcmstb_cpu_boot(unsigned int cpu)
> +{
> + pr_info("SMP: Booting CPU%d...\n", cpu);
> +
> + /*
> + * set the reset vector to point to the secondary_startup
> + * routine
> + */
> + cpu_set_boot_addr(cpu, virt_to_phys(brcmstb_secondary_startup));
> +
> + flush_cache_all();
Why? What does the new CPU need before its caches are coherent and up?
> +
> + /* unhalt the cpu */
> + cpu_rst_cfg_set(cpu, 0);
> +}
> +
> +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 */
> + );
This is odd. Why not allow GCC to allocate the register?
> +
> + /*
> + * Instruction barrier to ensure cache is really disabled before
> + * cleaning/invalidating the caches
> + */
> + isb();
I think you could use:
set_cr(get_cr() & ~CR_C))
Which would do all of the above (including the isb), and will get GCC to
allocate the register.
> +
> + 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();
Why do you need to invalidate the I-cache?
> +
> + /*
> + * 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 */
> + );
Surely you can use an output operand to get GCC to allocate the register
for you?
> +
> + /* Disable all IRQs for this CPU */
> + arch_local_irq_disable();
> +
> + per_cpu(per_cpu_sw_state, cpu) = 0;
Your caches are off at this point, so this could be going straight to
memory. Yet readers of this value aren't cleaning their caches before
reading this, so they could hit a stale cached copy.
> +
> + /*
> + * 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();
Why the nop first?
> + panic("Spurious interrupt on CPU %d received!\n", cpu);
> +}
> +
> +int brcmstb_cpu_kill(unsigned int cpu)
> +{
> + u32 tmp;
> +
> + pr_info("SMP: Powering down CPU%d...\n", cpu);
> +
> + while (per_cpu(per_cpu_sw_state, cpu))
> + ;
As this was written to with caches disabled, the cached copy of the
value (which this is reading) could be stale. Surely you need to
clean+invalidate the line for this value each time you read it to give
it a chance to update?
> +
> + /* 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 */
> + cpu_rst_cfg_set(cpu, 1);
> +
> + return 1;
> +}
> +
> +static int __init setup_hifcpubiuctrl_regs(struct device_node *np)
> +{
> + int rc = 0;
> + char *name;
> + int index;
> + struct device_node *syscon_np = NULL;
> +
> + name = "syscon-cpu";
> +
> + syscon_np = of_parse_phandle(np, name, 0);
> + if (!syscon_np) {
> + pr_err("can't find phandle %s\n", name);
> + rc = -EINVAL;
> + goto cleanup;
> + }
> +
> + cpubiuctrl_block = of_iomap(syscon_np, 0);
> + if (!cpubiuctrl_block) {
> + pr_err("iomap failed for cpubiuctrl_block\n");
> + rc = -EINVAL;
> + goto cleanup;
> + }
> +
> + index = 1;
> + rc = of_property_read_u32_index(np, name, index,
> + &cpu0_pwr_zone_ctrl_reg);
The index variable seems rather pointless. Why not just use the value
in-place?
> + if (rc) {
> + pr_err("failed to read %d from %s property (%d)\n", index, name,
> + rc);
It might be better to state _what_ you're looking for (what does the
value represent?).
> + rc = -EINVAL;
> + goto cleanup;
> + }
> +
> + index = 2;
> + rc = of_property_read_u32_index(np, name, index, &cpu_rst_cfg_reg);
Likewise for all of the above.
Thanks,
Mark.
On Wed, Jan 22, 2014 at 03:30:48AM +0000, Marc Carino wrote:
> Perform any CPU-specific initialization required on the
> Broadcom Brahma-15 core.
>
> Signed-off-by: Marc Carino <[email protected]>
> Acked-by: Florian Fainelli <[email protected]>
> ---
> 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
On the third posting, Will Deacon asked if the hwcap override was really
required [1]. Two postings later there's been no answer.
Is your CPUID_EXT_ISAR0 value wrong? If so, please add a comment to that
effect (as with __krait_proc_info).
Thanks,
Mark.
[1] http://lists.infradead.org/pipermail/linux-arm-kernel/2014-January/225895.html
On Wed, Jan 22, 2014 at 03:30:50AM +0000, Marc Carino wrote:
> Document the bindings that the Broadcom STB platform needs
> for proper bootup.
>
> Signed-off-by: Marc Carino <[email protected]>
> Acked-by: Florian Fainelli <[email protected]>
> ---
> .../devicetree/bindings/arm/brcm-brcmstb.txt | 95 ++++++++++++++++++++
> 1 files changed, 95 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..3c436cc
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/arm/brcm-brcmstb.txt
> @@ -0,0 +1,95 @@
> +ARM Broadcom STB platforms Device Tree Bindings
> +-----------------------------------------------
> +Boards with Broadcom Brahma15 ARM-based BCMxxxx (generally BCM7xxx variants)
> +SoC shall have the following DT organization:
> +
> +Required root node properties:
> + - compatible: "brcm,bcm<chip_id>", "brcm,brcmstb"
> +
> +example:
> +/ {
> + #address-cells = <2>;
> + #size-cells = <2>;
> + model = "Broadcom STB (bcm7445)";
> + compatible = "brcm,bcm7445", "brcm,brcmstb";
> +
> +Further, syscon nodes that map platform-specific registers used for general
> +system control is required:
> +
> + - compatible: "brcm,bcm<chip_id>-sun-top-ctrl", "syscon"
> + - compatible: "brcm,bcm<chip_id>-hif-cpubiuctrl", "syscon"
> + - compatible: "brcm,bcm<chip_id>-hif-continuation", "syscon"
> +
> +example:
> + rdb {
> + #address-cells = <1>;
> + #size-cells = <1>;
> + compatible = "simple-bus";
> + ranges = <0 0x00 0xf0000000 0x1000000>;
> +
> + sun_top_ctrl: syscon@404000 {
> + compatible = "brcm,bcm7445-sun-top-ctrl", "syscon";
> + reg = <0x404000 0x51c>;
> + };
> +
> + hif_cpubiuctrl: syscon@3e2400 {
> + compatible = "brcm,bcm7445-hif-cpubiuctrl", "syscon";
> + reg = <0x3e2400 0x5b4>;
> + };
> +
> + hif_continuation: syscon@452000 {
> + compatible = "brcm,bcm7445-hif-continuation", "syscon";
> + reg = <0x452000 0x100>;
> + };
> + };
> +
> +Lastly, nodes that allow for support of SMP initialization and reboot are
> +required:
> +
> +smpboot
> +-------
> +Required properties:
> +
> + - compatible
> + The string "brcm,brcmstb-smpboot".
> +
> + - syscon-cpu
> + A phandle / integer array property which lets the BSP know the location
> + of certain CPU power-on registers.
> +
> + The layout of the property is as follows:
> + o a phandle to the "hif_cpubiuctrl" syscon node
> + o offset to the base CPU power zone register
> + o offset to the base CPU reset register
How variable are these values?
> +
> + - syscon-cont
> + A phandle pointing to the syscon node which describes the CPU boot
> + continuation registers.
> + o a phandle to the "hif_continuation" syscon node
> +
> +example:
> + smpboot {
> + compatible = "brcm,brcmstb-smpboot";
> + syscon-cpu = <&hif_cpubiuctrl 0x88 0x178>;
> + syscon-cont = <&hif_continuation>;
> + };
This looks odd. This doesn't seem like a device, but rather a grouping
of disparate devices used for a particular software purpose.
> +
> +reboot
> +-------
> +Required properties
> +
> + - compatible
> + The string property "brcm,brcmstb-reboot".
> +
> + - syscon
> + A phandle / integer array that points to the syscon node which describes
> + the general system reset registers.
> + o a phandle to "sun_top_ctrl"
> + o offset to the "reset source enable" register
> + o offset to the "software master reset" register
How variable are these values?
> +
> +example:
> + reboot {
> + compatible = "brcm,brcmstb-reboot";
> + syscon = <&sun_top_ctrl 0x304 0x308>;
> + };
As with smpboot, this seems odd.
Thanks,
Mark.
On Wed, Jan 22, 2014 at 03:30:52AM +0000, Marc Carino wrote:
> Add a sample DTS which will allow bootup of a board populated
> with the BCM7445 chip.
>
> Signed-off-by: Marc Carino <[email protected]>
> Acked-by: Florian Fainelli <[email protected]>
> ---
> arch/arm/boot/dts/bcm7445.dts | 111 +++++++++++++++++++++++++++++++++++++++++
> 1 files changed, 111 insertions(+), 0 deletions(-)
> create mode 100644 arch/arm/boot/dts/bcm7445.dts
>
> diff --git a/arch/arm/boot/dts/bcm7445.dts b/arch/arm/boot/dts/bcm7445.dts
> new file mode 100644
> index 0000000..ffa3305
> --- /dev/null
> +++ b/arch/arm/boot/dts/bcm7445.dts
> @@ -0,0 +1,111 @@
> +/dts-v1/;
> +/include/ "skeleton.dtsi"
> +
> +/ {
> + #address-cells = <2>;
> + #size-cells = <2>;
> + model = "Broadcom STB (bcm7445)";
> + compatible = "brcm,bcm7445", "brcm,brcmstb";
> + interrupt-parent = <&gic>;
> +
> + chosen {};
> +
> + memory {
> + device_type = "memory";
> + reg = <0x00 0x00000000 0x00 0x40000000>,
> + <0x00 0x40000000 0x00 0x40000000>,
> + <0x00 0x80000000 0x00 0x40000000>;
> + };
As I commented on v3 [1], these are contiguous and can be described with
a single entry:
memory {
device_type = "memory";
reg = <0x0 0x00000000 0x0 0xc0000000>;
};
Is there any reason to have three entries?
Thanks,
Mark.
[1] http://lists.infradead.org/pipermail/linux-arm-kernel/2014-January/225899.html
Hi Mark,
>> +static void __init brcmstb_init_early(void)
>> +{
>> + add_preferred_console("ttyS", 0, "115200");
>> +}
>
> Is this really required?
I think I can drop this. It was a holdover from our older kernels.
>> + /*
>> + * set the reset vector to point to the secondary_startup
>> + * routine
>> + */
>> + cpu_set_boot_addr(cpu, virt_to_phys(brcmstb_secondary_startup));
>> +
>> + flush_cache_all();
>
> Why? What does the new CPU need before its caches are coherent and up?
Absolutely nothing! I should be able to drop this as well.
Regarding the CPU power-down sequence, I'll review it and make sure it follows the
"Processor power domain" sequence in the A15 TRM. For any deviations, I'll double-check
with our H/W designers to ensure there aren't any magic requirements unaccounted for.
Thank you for taking a deep-dive into the code! I'll make the appropriate modifications
per your suggestions.
Regards,
Marc C
On 01/24/2014 02:14 AM, Mark Rutland wrote:
> On Wed, Jan 22, 2014 at 03:30:45AM +0000, Marc Carino wrote:
>> 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 <[email protected]>
>> Acked-by: Florian Fainelli <[email protected]>
>> ---
>> 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 | 110 ++++++++++++
>> arch/arm/mach-bcm/brcmstb.h | 38 ++++
>> arch/arm/mach-bcm/headsmp-brcmstb.S | 34 ++++
>> arch/arm/mach-bcm/hotplug-brcmstb.c | 334 +++++++++++++++++++++++++++++++++++
>> 7 files changed, 535 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..7a6093d
>> --- /dev/null
>> +++ b/arch/arm/mach-bcm/brcmstb.c
>> @@ -0,0 +1,110 @@
>> +/*
>> + * 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,bcm7445",
>> + "brcm,brcmstb",
>> + NULL
>> +};
>> +
>> +static void __init brcmstb_init_early(void)
>> +{
>> + add_preferred_console("ttyS", 0, "115200");
>> +}
>
> Is this really required?
>
>> +
>> +/***********************************************************************
>> + * 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,
>> +#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..e49bde6
>> --- /dev/null
>> +++ b/arch/arm/mach-bcm/brcmstb.h
>> @@ -0,0 +1,38 @@
>> +/*
>> + * 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;
>> +#if defined(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
>> +
>> +#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
>
> __CPUINIT is either going or gone by now. This should disappear.
>
>> +
>> +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..ff4a732
>> --- /dev/null
>> +++ b/arch/arm/mach-bcm/hotplug-brcmstb.c
>> @@ -0,0 +1,334 @@
>> +/*
>> + * 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/regmap.h>
>> +#include <linux/smp.h>
>> +#include <linux/mfd/syscon.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 *cpubiuctrl_block;
>> +static void __iomem *hif_cont_block;
>> +static u32 cpu0_pwr_zone_ctrl_reg;
>> +static u32 cpu_rst_cfg_reg;
>> +static u32 hif_cont_reg;
>> +DEFINE_PER_CPU(int, per_cpu_sw_state);
>> +
>> +static void __iomem *pwr_ctrl_get_base(unsigned int cpu)
>> +{
>> + void __iomem *base = cpubiuctrl_block + cpu0_pwr_zone_ctrl_reg;
>> + base += (cpu * 4);
>
> CPU isn't guaranteed to be the physical CPU ID (MPIDR.Aff*). While it
> almost certainly will be, we can't guarantee it in the face of a kexec,
> for example.
>
> You can use cpu_logical_map(cpu) to get the physical ID.
>
>> + 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);
>> +}
>> +
>> +static void cpu_rst_cfg_set(int cpu, int set)
>> +{
>> + u32 val;
>> + val = readl_relaxed(cpubiuctrl_block + cpu_rst_cfg_reg);
>> + if (set)
>> + val |= BIT(cpu);
>> + else
>> + val &= ~BIT(cpu);
>
> Likewise here.
>
>> + writel_relaxed(val, cpubiuctrl_block + cpu_rst_cfg_reg);
>> +}
>> +
>> +static void cpu_set_boot_addr(int cpu, unsigned long boot_addr)
>> +{
>> + const int reg_ofs = cpu * 8;
>
> And here.
>
>> + writel_relaxed(0, hif_cont_block + hif_cont_reg + reg_ofs);
>> + writel_relaxed(boot_addr, hif_cont_block + hif_cont_reg + 4 + reg_ofs);
>> +}
>> +
>> +void brcmstb_cpu_boot(unsigned int cpu)
>> +{
>> + pr_info("SMP: Booting CPU%d...\n", cpu);
>> +
>> + /*
>> + * set the reset vector to point to the secondary_startup
>> + * routine
>> + */
>> + cpu_set_boot_addr(cpu, virt_to_phys(brcmstb_secondary_startup));
>> +
>> + flush_cache_all();
>
> Why? What does the new CPU need before its caches are coherent and up?
>
>> +
>> + /* unhalt the cpu */
>> + cpu_rst_cfg_set(cpu, 0);
>> +}
>> +
>> +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 */
>> + );
>
> This is odd. Why not allow GCC to allocate the register?
>
>> +
>> + /*
>> + * Instruction barrier to ensure cache is really disabled before
>> + * cleaning/invalidating the caches
>> + */
>> + isb();
>
> I think you could use:
>
> set_cr(get_cr() & ~CR_C))
>
> Which would do all of the above (including the isb), and will get GCC to
> allocate the register.
>
>> +
>> + 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();
>
> Why do you need to invalidate the I-cache?
>
>> +
>> + /*
>> + * 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 */
>> + );
>
> Surely you can use an output operand to get GCC to allocate the register
> for you?
>
>> +
>> + /* Disable all IRQs for this CPU */
>> + arch_local_irq_disable();
>> +
>> + per_cpu(per_cpu_sw_state, cpu) = 0;
>
> Your caches are off at this point, so this could be going straight to
> memory. Yet readers of this value aren't cleaning their caches before
> reading this, so they could hit a stale cached copy.
>
>> +
>> + /*
>> + * 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();
>
> Why the nop first?
>
>> + panic("Spurious interrupt on CPU %d received!\n", cpu);
>> +}
>> +
>> +int brcmstb_cpu_kill(unsigned int cpu)
>> +{
>> + u32 tmp;
>> +
>> + pr_info("SMP: Powering down CPU%d...\n", cpu);
>> +
>> + while (per_cpu(per_cpu_sw_state, cpu))
>> + ;
>
> As this was written to with caches disabled, the cached copy of the
> value (which this is reading) could be stale. Surely you need to
> clean+invalidate the line for this value each time you read it to give
> it a chance to update?
>
>> +
>> + /* 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 */
>> + cpu_rst_cfg_set(cpu, 1);
>> +
>> + return 1;
>> +}
>> +
>> +static int __init setup_hifcpubiuctrl_regs(struct device_node *np)
>> +{
>> + int rc = 0;
>> + char *name;
>> + int index;
>> + struct device_node *syscon_np = NULL;
>> +
>> + name = "syscon-cpu";
>> +
>> + syscon_np = of_parse_phandle(np, name, 0);
>> + if (!syscon_np) {
>> + pr_err("can't find phandle %s\n", name);
>> + rc = -EINVAL;
>> + goto cleanup;
>> + }
>> +
>> + cpubiuctrl_block = of_iomap(syscon_np, 0);
>> + if (!cpubiuctrl_block) {
>> + pr_err("iomap failed for cpubiuctrl_block\n");
>> + rc = -EINVAL;
>> + goto cleanup;
>> + }
>> +
>> + index = 1;
>> + rc = of_property_read_u32_index(np, name, index,
>> + &cpu0_pwr_zone_ctrl_reg);
>
> The index variable seems rather pointless. Why not just use the value
> in-place?
>
>> + if (rc) {
>> + pr_err("failed to read %d from %s property (%d)\n", index, name,
>> + rc);
>
> It might be better to state _what_ you're looking for (what does the
> value represent?).
>
>> + rc = -EINVAL;
>> + goto cleanup;
>> + }
>> +
>> + index = 2;
>> + rc = of_property_read_u32_index(np, name, index, &cpu_rst_cfg_reg);
>
> Likewise for all of the above.
>
> Thanks,
> Mark.
>
Hi Mark,
>> +reboot
>> +-------
>> +Required properties
>> +
>> + - compatible
>> + The string property "brcm,brcmstb-reboot".
>> +
>> + - syscon
>> + A phandle / integer array that points to the syscon node which describes
>> + the general system reset registers.
>> + o a phandle to "sun_top_ctrl"
>> + o offset to the "reset source enable" register
>> + o offset to the "software master reset" register
>
> How variable are these values?
Very much so. Future chips will have different register maps. Because of this, Arnd
suggested that we use 'syscon' and 'regmap' to alleviate this maintenance burden.
>> +example:
>> + smpboot {
>> + compatible = "brcm,brcmstb-smpboot";
>> + syscon-cpu = <&hif_cpubiuctrl 0x88 0x178>;
>> + syscon-cont = <&hif_continuation>;
>> + };
>
> This looks odd. This doesn't seem like a device, but rather a grouping
> of disparate devices used for a particular software purpose.
>
>> +
>> +example:
>> + reboot {
>> + compatible = "brcm,brcmstb-reboot";
>> + syscon = <&sun_top_ctrl 0x304 0x308>;
>> + };
>
> As with smpboot, this seems odd.
Sure. Our H/W designers unfortunately didn't put the boot and restart registers into a
logical grouping, or standard register interface. Instead, they're all over the place.
How do you suggest naming the nodes to indicate this?
Thanks,
Marc C
On 01/24/2014 03:03 AM, Mark Rutland wrote:
> On Wed, Jan 22, 2014 at 03:30:50AM +0000, Marc Carino wrote:
>> Document the bindings that the Broadcom STB platform needs
>> for proper bootup.
>>
>> Signed-off-by: Marc Carino <[email protected]>
>> Acked-by: Florian Fainelli <[email protected]>
>> ---
>> .../devicetree/bindings/arm/brcm-brcmstb.txt | 95 ++++++++++++++++++++
>> 1 files changed, 95 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..3c436cc
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/arm/brcm-brcmstb.txt
>> @@ -0,0 +1,95 @@
>> +ARM Broadcom STB platforms Device Tree Bindings
>> +-----------------------------------------------
>> +Boards with Broadcom Brahma15 ARM-based BCMxxxx (generally BCM7xxx variants)
>> +SoC shall have the following DT organization:
>> +
>> +Required root node properties:
>> + - compatible: "brcm,bcm<chip_id>", "brcm,brcmstb"
>> +
>> +example:
>> +/ {
>> + #address-cells = <2>;
>> + #size-cells = <2>;
>> + model = "Broadcom STB (bcm7445)";
>> + compatible = "brcm,bcm7445", "brcm,brcmstb";
>> +
>> +Further, syscon nodes that map platform-specific registers used for general
>> +system control is required:
>> +
>> + - compatible: "brcm,bcm<chip_id>-sun-top-ctrl", "syscon"
>> + - compatible: "brcm,bcm<chip_id>-hif-cpubiuctrl", "syscon"
>> + - compatible: "brcm,bcm<chip_id>-hif-continuation", "syscon"
>> +
>> +example:
>> + rdb {
>> + #address-cells = <1>;
>> + #size-cells = <1>;
>> + compatible = "simple-bus";
>> + ranges = <0 0x00 0xf0000000 0x1000000>;
>> +
>> + sun_top_ctrl: syscon@404000 {
>> + compatible = "brcm,bcm7445-sun-top-ctrl", "syscon";
>> + reg = <0x404000 0x51c>;
>> + };
>> +
>> + hif_cpubiuctrl: syscon@3e2400 {
>> + compatible = "brcm,bcm7445-hif-cpubiuctrl", "syscon";
>> + reg = <0x3e2400 0x5b4>;
>> + };
>> +
>> + hif_continuation: syscon@452000 {
>> + compatible = "brcm,bcm7445-hif-continuation", "syscon";
>> + reg = <0x452000 0x100>;
>> + };
>> + };
>> +
>> +Lastly, nodes that allow for support of SMP initialization and reboot are
>> +required:
>> +
>> +smpboot
>> +-------
>> +Required properties:
>> +
>> + - compatible
>> + The string "brcm,brcmstb-smpboot".
>> +
>> + - syscon-cpu
>> + A phandle / integer array property which lets the BSP know the location
>> + of certain CPU power-on registers.
>> +
>> + The layout of the property is as follows:
>> + o a phandle to the "hif_cpubiuctrl" syscon node
>> + o offset to the base CPU power zone register
>> + o offset to the base CPU reset register
>
> How variable are these values?
>
>> +
>> + - syscon-cont
>> + A phandle pointing to the syscon node which describes the CPU boot
>> + continuation registers.
>> + o a phandle to the "hif_continuation" syscon node
>> +
>> +example:
>> + smpboot {
>> + compatible = "brcm,brcmstb-smpboot";
>> + syscon-cpu = <&hif_cpubiuctrl 0x88 0x178>;
>> + syscon-cont = <&hif_continuation>;
>> + };
>
> This looks odd. This doesn't seem like a device, but rather a grouping
> of disparate devices used for a particular software purpose.
>
>> +
>> +reboot
>> +-------
>> +Required properties
>> +
>> + - compatible
>> + The string property "brcm,brcmstb-reboot".
>> +
>> + - syscon
>> + A phandle / integer array that points to the syscon node which describes
>> + the general system reset registers.
>> + o a phandle to "sun_top_ctrl"
>> + o offset to the "reset source enable" register
>> + o offset to the "software master reset" register
>
> How variable are these values?
>
>> +
>> +example:
>> + reboot {
>> + compatible = "brcm,brcmstb-reboot";
>> + syscon = <&sun_top_ctrl 0x304 0x308>;
>> + };
>
> As with smpboot, this seems odd.
>
> Thanks,
> Mark.
>
Hi Mark,
> As I commented on v3 [1], these are contiguous and can be described with
> a single entry:
>
> memory {
> device_type = "memory";
> reg = <0x0 0x00000000 0x0 0xc0000000>;
> };
>
> Is there any reason to have three entries?
Oopsies, sorry for missing that.
On BCM7445 and derivatives, there are 3 memory controllers. For each memory controller,
the first 1GB of physical DRAM is mapped to:
* 0x00_0000_0000
* 0x00_4000_0000
* 0x00_8000_0000
The memory controllers aren't interleaved. So, it's possible for the SoC to have a
discontiguous memory-mapping, where a designer chooses not to populate physical DRAM in
the middle.
The 'reg' property was broken-up to have each chunk of memory given a dedicated memblock.
All that said, if you like, I can rework the patch as you've suggested.
Thanks,
Marc C
On 01/24/2014 03:09 AM, Mark Rutland wrote:
> On Wed, Jan 22, 2014 at 03:30:52AM +0000, Marc Carino wrote:
>> Add a sample DTS which will allow bootup of a board populated
>> with the BCM7445 chip.
>>
>> Signed-off-by: Marc Carino <[email protected]>
>> Acked-by: Florian Fainelli <[email protected]>
>> ---
>> arch/arm/boot/dts/bcm7445.dts | 111 +++++++++++++++++++++++++++++++++++++++++
>> 1 files changed, 111 insertions(+), 0 deletions(-)
>> create mode 100644 arch/arm/boot/dts/bcm7445.dts
>>
>> diff --git a/arch/arm/boot/dts/bcm7445.dts b/arch/arm/boot/dts/bcm7445.dts
>> new file mode 100644
>> index 0000000..ffa3305
>> --- /dev/null
>> +++ b/arch/arm/boot/dts/bcm7445.dts
>> @@ -0,0 +1,111 @@
>> +/dts-v1/;
>> +/include/ "skeleton.dtsi"
>> +
>> +/ {
>> + #address-cells = <2>;
>> + #size-cells = <2>;
>> + model = "Broadcom STB (bcm7445)";
>> + compatible = "brcm,bcm7445", "brcm,brcmstb";
>> + interrupt-parent = <&gic>;
>> +
>> + chosen {};
>> +
>> + memory {
>> + device_type = "memory";
>> + reg = <0x00 0x00000000 0x00 0x40000000>,
>> + <0x00 0x40000000 0x00 0x40000000>,
>> + <0x00 0x80000000 0x00 0x40000000>;
>> + };
>
> As I commented on v3 [1], these are contiguous and can be described with
> a single entry:
>
> memory {
> device_type = "memory";
> reg = <0x0 0x00000000 0x0 0xc0000000>;
> };
>
> Is there any reason to have three entries?
>
> Thanks,
> Mark.
>
> [1] http://lists.infradead.org/pipermail/linux-arm-kernel/2014-January/225899.html
>