From patchwork Mon Jul 21 21:07:56 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Brian Norris X-Patchwork-Id: 4598361 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id C1B86C0515 for ; Mon, 21 Jul 2014 21:13:16 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 711FD20127 for ; Mon, 21 Jul 2014 21:13:15 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 1B6F420120 for ; Mon, 21 Jul 2014 21:13:14 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1X9KqH-00036x-43; Mon, 21 Jul 2014 21:09:53 +0000 Received: from mail-pa0-x231.google.com ([2607:f8b0:400e:c03::231]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1X9Kpw-0002Nk-7I for linux-arm-kernel@lists.infradead.org; Mon, 21 Jul 2014 21:09:33 +0000 Received: by mail-pa0-f49.google.com with SMTP id hz1so10386865pad.36 for ; Mon, 21 Jul 2014 14:09:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=BLhyIixvIP0RBOYdCqIZM1MtizAelbFZK2v1J8tiHBM=; b=Gh4k/eJQhme7yp+F5gcX45O8XHvn+JMDq1QZlXzh26ZF8Eewoxvb+CWqTuPLOxbdPE y1XSHz54Zwf2ZMRa8lhwjoEk+BLMTTjHwknun5GX1c3R21788B5yr7fcWYwWM/XCeBGA L/JPE4A0IAQoDU6POE9cZfJ5KF24HKnHYZxaUd/cMHCWZQVnQ80cI2H0iAS8RbbIOafr XA32+z5N0jXtcfVC8lsmf6D+WHUjKF/7oCNC8/rze1ZxZenSMCzfeozwJJxE33p0NwrT 2gIXfTRsklUDMHmMkQ0jUatFjmjPXEfu8ri+qdUd7wQZMByRQ9ZfHeXgIuhX1mup51Y0 Nfeg== X-Received: by 10.68.252.7 with SMTP id zo7mr17327592pbc.102.1405976950796; Mon, 21 Jul 2014 14:09:10 -0700 (PDT) Received: from ld-irv-0074.broadcom.com (5520-maca-inet1-outside.broadcom.com. [216.31.211.11]) by mx.google.com with ESMTPSA id c17sm20387643pdm.33.2014.07.21.14.09.09 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 21 Jul 2014 14:09:10 -0700 (PDT) From: Brian Norris To: Arnd Bergmann , Olof Johansson Subject: [PATCH v8 01/11] ARM: brcmstb: add infrastructure for ARM-based Broadcom STB SoCs Date: Mon, 21 Jul 2014 14:07:56 -0700 Message-Id: <1405976886-27807-2-git-send-email-computersforpeace@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1405976886-27807-1-git-send-email-computersforpeace@gmail.com> References: <1405976886-27807-1-git-send-email-computersforpeace@gmail.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140721_140932_332821_038685C6 X-CRM114-Status: GOOD ( 23.88 ) X-Spam-Score: -0.8 (/) Cc: devicetree@vger.kernel.org, Florian Fainelli , Russell King , Christian Daudt , Linux Kernel , Matt Porter , Marc Carino , Gregory Fong , Brian Norris , linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-1.8 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RP_MATCHES_RCVD, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=no version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Marc Carino 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 Signed-off-by: Brian Norris --- arch/arm/configs/multi_v7_defconfig | 1 + arch/arm/mach-bcm/Kconfig | 14 ++ arch/arm/mach-bcm/Makefile | 5 + arch/arm/mach-bcm/brcmstb.c | 28 +++ arch/arm/mach-bcm/brcmstb.h | 19 ++ arch/arm/mach-bcm/headsmp-brcmstb.S | 33 ++++ arch/arm/mach-bcm/platsmp-brcmstb.c | 363 ++++++++++++++++++++++++++++++++++++ 7 files changed, 463 insertions(+) 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/platsmp-brcmstb.c diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index 534836497998..bf0df396a3cf 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -19,6 +19,7 @@ CONFIG_MACH_DOVE=y CONFIG_ARCH_BCM=y CONFIG_ARCH_BCM_MOBILE=y CONFIG_ARCH_BCM_5301X=y +CONFIG_ARCH_BRCMSTB=y CONFIG_ARCH_BERLIN=y CONFIG_MACH_BERLIN_BG2=y CONFIG_MACH_BERLIN_BG2CD=y diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig index 41c839167e87..0073633e7699 100644 --- a/arch/arm/mach-bcm/Kconfig +++ b/arch/arm/mach-bcm/Kconfig @@ -87,4 +87,18 @@ config ARCH_BCM_5301X different SoC or with the older BCM47XX and BCM53XX based network SoC using a MIPS CPU, they are supported by arch/mips/bcm47xx +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. + endif diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile index 731292114975..f3665121729b 100644 --- a/arch/arm/mach-bcm/Makefile +++ b/arch/arm/mach-bcm/Makefile @@ -30,3 +30,8 @@ obj-$(CONFIG_ARCH_BCM2835) += board_bcm2835.o # BCM5301X obj-$(CONFIG_ARCH_BCM_5301X) += bcm_5301x.o + +ifeq ($(CONFIG_ARCH_BRCMSTB),y) +obj-y += brcmstb.o +obj-$(CONFIG_SMP) += headsmp-brcmstb.o platsmp-brcmstb.o +endif diff --git a/arch/arm/mach-bcm/brcmstb.c b/arch/arm/mach-bcm/brcmstb.c new file mode 100644 index 000000000000..60a5afa06ed7 --- /dev/null +++ b/arch/arm/mach-bcm/brcmstb.c @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2013-2014 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 +#include + +#include +#include + +static const char *brcmstb_match[] __initconst = { + "brcm,bcm7445", + "brcm,brcmstb", + NULL +}; + +DT_MACHINE_START(BRCMSTB, "Broadcom STB (Flattened Device Tree)") + .dt_compat = brcmstb_match, +MACHINE_END diff --git a/arch/arm/mach-bcm/brcmstb.h b/arch/arm/mach-bcm/brcmstb.h new file mode 100644 index 000000000000..ec0c3d112b36 --- /dev/null +++ b/arch/arm/mach-bcm/brcmstb.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2013-2014 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__ + +void brcmstb_secondary_startup(void); + +#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 000000000000..199c1ea58248 --- /dev/null +++ b/arch/arm/mach-bcm/headsmp-brcmstb.S @@ -0,0 +1,33 @@ +/* + * SMP boot code for secondary CPUs + * Based on arch/arm/mach-tegra/headsmp.S + * + * Copyright (C) 2010 NVIDIA, Inc. + * Copyright (C) 2013-2014 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 +#include +#include + + .section ".text.head", "ax" + +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/platsmp-brcmstb.c b/arch/arm/mach-bcm/platsmp-brcmstb.c new file mode 100644 index 000000000000..af780e9c23a6 --- /dev/null +++ b/arch/arm/mach-bcm/platsmp-brcmstb.c @@ -0,0 +1,363 @@ +/* + * Broadcom STB CPU SMP and hotplug support for ARM + * + * Copyright (C) 2013-2014 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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(12), + ZONE_PWR_OFF_STATE_MASK = BIT(25), + 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), + CPU0_PWR_ZONE_CTRL_REG = 1, + CPU_RESET_CONFIG_REG = 2, +}; + +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; + +#ifdef CONFIG_HOTPLUG_CPU +static DEFINE_PER_CPU_ALIGNED(int, per_cpu_sw_state); + +static int per_cpu_sw_state_rd(u32 cpu) +{ + sync_cache_r(SHIFT_PERCPU_PTR(&per_cpu_sw_state, per_cpu_offset(cpu))); + return per_cpu(per_cpu_sw_state, cpu); +} + +static void per_cpu_sw_state_wr(u32 cpu, int val) +{ + per_cpu(per_cpu_sw_state, cpu) = val; + dmb(); + sync_cache_w(SHIFT_PERCPU_PTR(&per_cpu_sw_state, per_cpu_offset(cpu))); + dsb_sev(); +} +#else +static inline void per_cpu_sw_state_wr(u32 cpu, int val) { } +#endif + +static void __iomem *pwr_ctrl_get_base(u32 cpu) +{ + void __iomem *base = cpubiuctrl_block + cpu0_pwr_zone_ctrl_reg; + base += (cpu_logical_map(cpu) * 4); + return base; +} + +static u32 pwr_ctrl_rd(u32 cpu) +{ + void __iomem *base = pwr_ctrl_get_base(cpu); + return readl_relaxed(base); +} + +static void pwr_ctrl_wr(u32 cpu, u32 val) +{ + void __iomem *base = pwr_ctrl_get_base(cpu); + writel(val, base); +} + +static void cpu_rst_cfg_set(u32 cpu, int set) +{ + u32 val; + val = readl_relaxed(cpubiuctrl_block + cpu_rst_cfg_reg); + if (set) + val |= BIT(cpu_logical_map(cpu)); + else + val &= ~BIT(cpu_logical_map(cpu)); + writel_relaxed(val, cpubiuctrl_block + cpu_rst_cfg_reg); +} + +static void cpu_set_boot_addr(u32 cpu, unsigned long boot_addr) +{ + const int reg_ofs = cpu_logical_map(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); +} + +static void brcmstb_cpu_boot(u32 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)); + + /* unhalt the cpu */ + cpu_rst_cfg_set(cpu, 0); +} + +static void brcmstb_cpu_power_on(u32 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_sw_state_wr(cpu, 1); +} + +static int brcmstb_cpu_get_power_state(u32 cpu) +{ + int tmp = pwr_ctrl_rd(cpu); + return (tmp & ZONE_RESET_STATE_MASK) ? 0 : 1; +} + +#ifdef CONFIG_HOTPLUG_CPU + +static void brcmstb_cpu_die(u32 cpu) +{ + v7_exit_coherency_flush(all); + + /* Prevent all interrupts from reaching this CPU. */ + arch_local_irq_disable(); + + /* + * Final full barrier to ensure everything before this instruction has + * quiesced. + */ + isb(); + dsb(); + + per_cpu_sw_state_wr(cpu, 0); + + /* Sit and wait to die */ + wfi(); + + /* We should never get here... */ + panic("Spurious interrupt on CPU %d received!\n", cpu); +} + +static int brcmstb_cpu_kill(u32 cpu) +{ + u32 tmp; + + pr_info("SMP: Powering down CPU%d...\n", cpu); + + while (per_cpu_sw_state_rd(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; +} + +#endif /* CONFIG_HOTPLUG_CPU */ + +static int __init setup_hifcpubiuctrl_regs(struct device_node *np) +{ + int rc = 0; + char *name; + 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; + } + + rc = of_property_read_u32_index(np, name, CPU0_PWR_ZONE_CTRL_REG, + &cpu0_pwr_zone_ctrl_reg); + if (rc) { + pr_err("failed to read 1st entry from %s property (%d)\n", name, + rc); + rc = -EINVAL; + goto cleanup; + } + + rc = of_property_read_u32_index(np, name, CPU_RESET_CONFIG_REG, + &cpu_rst_cfg_reg); + if (rc) { + pr_err("failed to read 2nd entry from %s property (%d)\n", 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; +} + +static 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; +} + +static DEFINE_SPINLOCK(boot_lock); + +static void brcmstb_secondary_init(unsigned int cpu) +{ + /* + * Synchronise with the boot thread. + */ + spin_lock(&boot_lock); + spin_unlock(&boot_lock); +} + +static int 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; +} + +static 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 +}; + +CPU_METHOD_OF_DECLARE(brcmstb_smp, "brcm,brahma-b15", &brcmstb_smp_ops);