From patchwork Tue Apr 15 13:12:51 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Elder X-Patchwork-Id: 28412 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-pd0-f200.google.com (mail-pd0-f200.google.com [209.85.192.200]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 8393B2036A for ; Tue, 15 Apr 2014 13:14:01 +0000 (UTC) Received: by mail-pd0-f200.google.com with SMTP id p10sf32807406pdj.7 for ; Tue, 15 Apr 2014 06:14:00 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:in-reply-to:references:sender:precedence:list-id :x-original-sender:x-original-authentication-results:mailing-list :list-post:list-help:list-archive:list-unsubscribe; bh=4KggzTRI3XYZnb+9ju0eVuIjLQgJ0rCTWRD6k3eJoXg=; b=RGxNvkcIS0nxs3VEsfGxJUgxzMWlZjkEkRhM/9wWlHrHA8/6Rc+vAYlTyei2JuUEth ZHVUsDiVoDCLPgPY2nB4af+S1AGz6Ipf9szenNriRY5vKJcc3vOdJ01GXR+42Y7j75fF sk0uxIutY+ye9edciI2Uk+5p5sjk30cRaydeuS893K6nwZ/Xr0xKT5BFTKwmjT5gw/XB JNCTMDH6FYszU8kP+lY/yWigbyYFhzjNB/sO7PSpDC3YcPchKyQUrvthifE/44sbobmq jqDbEWMgEdyMxZdKCpzprnyx2uUVEkHQ8Q4Tug1NXc3FwLYltz9JL+FmmdW9jKP7euQ9 6FzA== X-Gm-Message-State: ALoCoQn/IEIaE7u+Vqo7N4/wFMKxeYV6wNvqdu6cc/YJJWmJbJ7mzuLrJjC6ttl/wDxDpxaOOdV1 X-Received: by 10.66.241.8 with SMTP id we8mr851875pac.16.1397567640701; Tue, 15 Apr 2014 06:14:00 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.88.229 with SMTP id t92ls107990qgd.9.gmail; Tue, 15 Apr 2014 06:14:00 -0700 (PDT) X-Received: by 10.52.65.132 with SMTP id x4mr1135878vds.36.1397567640567; Tue, 15 Apr 2014 06:14:00 -0700 (PDT) Received: from mail-ve0-f174.google.com (mail-ve0-f174.google.com [209.85.128.174]) by mx.google.com with ESMTPS id p8si3396818vef.68.2014.04.15.06.14.00 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 15 Apr 2014 06:14:00 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.128.174 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.128.174; Received: by mail-ve0-f174.google.com with SMTP id oz11so8914946veb.5 for ; Tue, 15 Apr 2014 06:14:00 -0700 (PDT) X-Received: by 10.220.44.20 with SMTP id y20mr19422vce.60.1397567640489; Tue, 15 Apr 2014 06:14:00 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.220.221.72 with SMTP id ib8csp230546vcb; Tue, 15 Apr 2014 06:13:59 -0700 (PDT) X-Received: by 10.68.99.194 with SMTP id es2mr1929739pbb.100.1397567639646; Tue, 15 Apr 2014 06:13:59 -0700 (PDT) Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id xf3si7550461pab.384.2014.04.15.06.13.59; Tue, 15 Apr 2014 06:13:59 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754633AbaDONNE (ORCPT + 26 others); Tue, 15 Apr 2014 09:13:04 -0400 Received: from mail-ie0-f171.google.com ([209.85.223.171]:48887 "EHLO mail-ie0-f171.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754411AbaDONM7 (ORCPT ); Tue, 15 Apr 2014 09:12:59 -0400 Received: by mail-ie0-f171.google.com with SMTP id ar20so9360358iec.30 for ; Tue, 15 Apr 2014 06:12:58 -0700 (PDT) X-Received: by 10.50.62.178 with SMTP id z18mr22775336igr.49.1397567578542; Tue, 15 Apr 2014 06:12:58 -0700 (PDT) Received: from localhost.localdomain (c-71-195-31-37.hsd1.mn.comcast.net. [71.195.31.37]) by mx.google.com with ESMTPSA id lp5sm5450880igb.1.2014.04.15.06.12.57 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 15 Apr 2014 06:12:57 -0700 (PDT) From: Alex Elder To: mporter@linaro.org, bcm@fixthebug.org, linux@arm.linux.org.uk, devicetree@vger.kernel.org, arnd@arndb.de, sboyd@codeaurora.org Cc: bcm-kernel-feedback-list@broadcom.com, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 2/5] ARM: add SMP support for Broadcom mobile SoCs Date: Tue, 15 Apr 2014 08:12:51 -0500 Message-Id: <1397567574-31599-3-git-send-email-elder@linaro.org> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1397567574-31599-1-git-send-email-elder@linaro.org> References: <1397567574-31599-1-git-send-email-elder@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: list List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: elder@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.128.174 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , This patch adds SMP support for BCM281XX and BCM21664 family SoCs. This feature is controlled with a distinct config option such that a SMP-enabled multi-v7 binary can be configured to run these SoCs in uniprocessor mode. Since this SMP functionality is used for multiple Broadcom mobile chip families the config option is called ARCH_BCM_MOBILE_SMP (for lack of a better name). On SoCs of this type, the secondary core is not held in reset on power-on. Instead it loops in a ROM-based holding pen. To release it, one must write into a special register a jump address whose low-order bits have been replaced with a secondary core's id, then trigger an event with SEV. On receipt of an event, the ROM code will examine the register's contents, and if the low-order bits match its cpu id, it will clear them and write the value back to the register just prior to jumping to the address specified. The location of the special register is defined in the device tree using a "secondary-boot-reg" property in a node whose "enable-method" matches. Derived from code originally provided by Ray Jui Signed-off-by: Alex Elder --- arch/arm/mach-bcm/Kconfig | 18 +++- arch/arm/mach-bcm/Makefile | 3 + arch/arm/mach-bcm/platsmp.c | 194 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 212 insertions(+), 3 deletions(-) create mode 100644 arch/arm/mach-bcm/platsmp.c diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig index 5f5740f..336fc6f 100644 --- a/arch/arm/mach-bcm/Kconfig +++ b/arch/arm/mach-bcm/Kconfig @@ -14,7 +14,6 @@ config ARCH_BCM_MOBILE depends on MMU select ARCH_REQUIRE_GPIOLIB select ARM_ERRATA_754322 - select ARM_ERRATA_764369 if SMP select ARM_GIC select GPIO_BCM_KONA select TICK_ONESHOT @@ -31,18 +30,31 @@ menu "Broadcom Mobile SoC Selection" config ARCH_BCM_281XX bool "Broadcom BCM281XX SoC family" default y + select HAVE_SMP help - Enable support for the the BCM281XX family, which includes + Enable support for the BCM281XX family, which includes BCM11130, BCM11140, BCM11351, BCM28145 and BCM28155 variants. config ARCH_BCM_21664 bool "Broadcom BCM21664 SoC family" default y + select HAVE_SMP help - Enable support for the the BCM21664 family, which includes + Enable support for the BCM21664 family, which includes BCM21663 and BCM21664 variants. +config ARCH_BCM_MOBILE_SMP + bool "Broadcom mobile SoC SMP support" + depends on (ARCH_BCM_281XX || ARCH_BCM_21664) && SMP + default y + select HAVE_ARM_SCU + select ARM_ERRATA_764369 + help + SMP support for the BCM281XX and BCM21664 SoC families. + Provided as an option so SMP support for SoCs of this type + can be disabled for an SMP-enabled kernel. + endmenu endif diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile index 7fb9b04..08c01a9 100644 --- a/arch/arm/mach-bcm/Makefile +++ b/arch/arm/mach-bcm/Makefile @@ -16,6 +16,9 @@ obj-$(CONFIG_ARCH_BCM_281XX) += board_bcm281xx.o # BCM21664 obj-$(CONFIG_ARCH_BCM_21664) += board_bcm21664.o +# BCM281XX and BCM21664 SMP support +obj-$(CONFIG_ARCH_BCM_MOBILE_SMP) += platsmp.o + # BCM281XX and BCM21664 L2 cache control obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm_kona_smc.o bcm_kona_smc_asm.o kona.o plus_sec := $(call as-instr,.arch_extension sec,+sec) diff --git a/arch/arm/mach-bcm/platsmp.c b/arch/arm/mach-bcm/platsmp.c new file mode 100644 index 0000000..46a64f2 --- /dev/null +++ b/arch/arm/mach-bcm/platsmp.c @@ -0,0 +1,194 @@ +/* + * Copyright (C) 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 + +/* Size of mapped Cortex A9 SCU address space */ +#define SCU_SIZE 0x58 + +#define SECONDARY_TIMEOUT_NS NSEC_PER_MSEC /* 1 msec (in nanoseconds) */ +#define BOOT_ADDR_CPUID_MASK 0x3 + +/* Name of device node property defining secondary boot register location */ +#define OF_SECONDARY_BOOT "secondary-boot-reg" + +/* I/O address of register used to coordinate secondary core startup */ +static u32 secondary_boot; + +/* + * Enable the Cortex A9 Snoop Control Unit + * + * By the time this is called we already know there are multiple + * cores present. We assume we're running on a Cortex A9 processor, + * so any trouble getting the base address register or getting the + * SCU base is a problem. + * + * Return 0 if successful or an error code otherwise. + */ +static int __init scu_a9_enable(void) +{ + unsigned long config_base; + void __iomem *scu_base; + + if (!scu_a9_has_base()) { + pr_err("no configuration base address register!\n"); + return -ENXIO; + } + + /* Config base address register value is zero for uniprocessor */ + config_base = scu_a9_get_base(); + if (!config_base) { + pr_err("hardware reports only one core; disabling SMP\n"); + return -ENOENT; + } + + scu_base = ioremap((phys_addr_t)config_base, SCU_SIZE); + if (!scu_base) { + pr_err("failed to remap config base (%lu/%u) for SCU\n", + config_base, SCU_SIZE); + return -ENOMEM; + } + + scu_enable(scu_base); + + iounmap(scu_base); /* That's the last we'll need of this */ + + return 0; +} + +static void __init bcm_smp_prepare_cpus(unsigned int max_cpus) +{ + static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 }; + int ret; + + /* Enable SCU on Cortex A9 based SoCs */ + ret = scu_a9_enable(); + if (!ret) + return; + + /* + * If we have a uniprocessor, make sure the CPU present map + * reflects that. Bail on any other failure to enable the SCU. + */ + if (ret == -ENOENT) + init_cpu_present(&only_cpu_0); + else + BUG(); +} + +/* + * Secondary startup method setup routine to extract the location of + * the secondary boot register from a "cpu" or "cpus" device tree + * node. Only the first seen secondary boot register value is used; + * any others are ignored. The secondary boot register value must be + * non-zero. + * + * Returns 0 if successful or an error code otherwise. + */ +static int __init of_enable_method_setup(struct device_node *node) +{ + int ret; + + /* Ignore all but the first one specified */ + if (secondary_boot) + return 0; + + ret = of_property_read_u32(node, OF_SECONDARY_BOOT, &secondary_boot); + if (ret) + pr_err("%s: missing/invalid " OF_SECONDARY_BOOT " property\n", + node->name); + + return ret; +} + +/* + * The ROM code has the secondary cores looping, waiting for an event. + * When an event occurs each core examines the bottom two bits of the + * secondary boot register. When a core finds those bits contain its + * own core id, it performs initialization, including computing its boot + * address by clearing the boot register value's bottom two bits. The + * core signals that it is beginning its execution by writing its boot + * address back to the secondary boot register, and finally jumps to + * that address. + * + * So to start a core executing we need to: + * - Encode the (hardware) CPU id with the bottom bits of the secondary + * start address. + * - Write that value into the secondary boot register. + * - Generate an event to wake up the secondary CPU(s). + * - Wait for the secondary boot register to be re-written, which + * indicates the secondary core has started. + */ +static int bcm_boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + void __iomem *boot_reg; + phys_addr_t boot_func; + u64 start_clock; + u32 cpu_id; + u32 boot_val; + bool timeout = false; + + cpu_id = cpu_logical_map(cpu); + if (cpu_id & ~BOOT_ADDR_CPUID_MASK) { + pr_err("bad cpu id (%u > %u)\n", cpu_id, BOOT_ADDR_CPUID_MASK); + return -EINVAL; + } + + if (!secondary_boot) { + pr_err("required secondary boot register not specified\n"); + return -EINVAL; + } + + boot_reg = ioremap_nocache((phys_addr_t)secondary_boot, sizeof(u32)); + if (!boot_reg) { + pr_err("unable to map boot register for cpu %u\n", cpu_id); + return -ENOSYS; + } + + boot_func = virt_to_phys(secondary_startup); + BUG_ON(boot_func & BOOT_ADDR_CPUID_MASK); + BUG_ON(boot_func > (phys_addr_t)U32_MAX); + + boot_val = (u32)boot_func | cpu_id; + writel_relaxed(boot_val, boot_reg); + + sev(); + + start_clock = local_clock(); + while (!timeout && readl_relaxed(boot_reg) == boot_val) + timeout = local_clock() - start_clock > SECONDARY_TIMEOUT_NS; + + iounmap(boot_reg); + + if (!timeout) + return 0; + + pr_err("timeout waiting for cpu %u to start\n", cpu_id); + + return -ENOSYS; +} + +static struct smp_operations bcm_smp_ops __initdata = { + .smp_prepare_cpus = bcm_smp_prepare_cpus, + .smp_boot_secondary = bcm_boot_secondary, +}; +CPU_METHOD_OF_DECLARE_SETUP(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method", + &of_enable_method_setup, &bcm_smp_ops);