Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
+256
View File
@@ -0,0 +1,256 @@
# SPDX-License-Identifier: GPL-2.0
menuconfig ARCH_BCM
bool "Broadcom SoC Support"
depends on ARCH_MULTI_V6_V7
help
This enables support for Broadcom ARM based SoC chips
if ARCH_BCM
comment "IPROC architected SoCs"
config ARCH_BCM_IPROC
bool
select ARM_GIC
select CACHE_L2X0
select HAVE_ARM_SCU if SMP
select HAVE_ARM_TWD if SMP
select ARM_GLOBAL_TIMER
select CLKSRC_MMIO
select GPIOLIB
select ARM_AMBA
select PINCTRL
help
This enables support for systems based on Broadcom IPROC architected SoCs.
The IPROC complex contains one or more ARM CPUs along with common
core peripherals. Application specific SoCs are created by adding a
uArchitecture containing peripherals outside of the IPROC complex.
Currently supported SoCs are Cygnus.
config ARCH_BCM_CYGNUS
bool "Broadcom Cygnus Support"
depends on ARCH_MULTI_V7
select ARCH_BCM_IPROC
help
Enable support for the Cygnus family,
which includes the following variants:
BCM11300, BCM11320, BCM11350, BCM11360,
BCM58300, BCM58302, BCM58303, BCM58305.
config ARCH_BCM_HR2
bool "Broadcom Hurricane 2 SoC support"
depends on ARCH_MULTI_V7
select ARCH_BCM_IPROC
help
Enable support for the Hurricane 2 family,
which includes the following variants:
BCM53342, BCM53343, BCM53344, BCM53346.
config ARCH_BCM_NSP
bool "Broadcom Northstar Plus SoC Support"
depends on ARCH_MULTI_V7
select ARCH_BCM_IPROC
select ARM_ERRATA_754322
select ARM_ERRATA_775420
select ARM_ERRATA_764369 if SMP
select ARM_TIMER_SP804
help
Support for Broadcom Northstar Plus SoC.
Broadcom Northstar Plus family of SoCs are used for switching control
and management applications as well as residential router/gateway
applications. The SoC features dual core Cortex A9 ARM CPUs,
integrating several peripheral interfaces including multiple Gigabit
Ethernet PHYs, DDR3 memory, PCIE Gen-2, USB 2.0 and USB 3.0, serial and
NAND flash, SATA and several other IO controllers.
config ARCH_BCM_5301X
bool "Broadcom BCM470X / BCM5301X ARM SoC"
depends on ARCH_MULTI_V7
select ARCH_BCM_IPROC
select ARM_ERRATA_754322
select ARM_ERRATA_775420
select ARM_ERRATA_764369 if SMP
help
Support for Broadcom BCM470X and BCM5301X SoCs with ARM CPU cores.
This is a network SoC line mostly used in home routers and
wifi access points, its internal name is Northstar.
This includes the following SoC: BCM53010, BCM53011, BCM53012,
BCM53014, BCM53015, BCM53016, BCM53017, BCM53018, BCM4707,
BCM4708 and BCM4709.
Do not confuse this with the BCM4760 which is a totally
different SoC or with the older BCM47XX and BCM53XX based
network SoC using a MIPS CPU, they are supported by arch/mips/bcm47xx
comment "KONA architected SoCs"
config ARCH_BCM_MOBILE
bool
select GPIOLIB
select ARM_ERRATA_754322
select ARM_ERRATA_775420
select ARM_GIC
select GPIO_BCM_KONA
select HAVE_ARM_ARCH_TIMER
select PINCTRL
select ARCH_BCM_MOBILE_SMP if SMP
select BCM_KONA_TIMER
help
This enables support for systems based on Broadcom mobile SoCs.
config ARCH_BCM_281XX
bool "Broadcom BCM281XX SoC family"
depends on ARCH_MULTI_V7
select ARCH_BCM_MOBILE
help
Enable support for the BCM281XX family, which includes
BCM11130, BCM11140, BCM11351, BCM28145 and BCM28155
variants.
config ARCH_BCM_21664
bool "Broadcom BCM21664 SoC family"
depends on ARCH_MULTI_V7
select ARCH_BCM_MOBILE
help
Enable support for the BCM21664 family, which includes
BCM21663 and BCM21664 variants.
config ARCH_BCM_23550
bool "Broadcom BCM23550 SoC"
depends on ARCH_MULTI_V7
select ARCH_BCM_MOBILE
help
Enable support for the BCM23550.
config ARCH_BCM_MOBILE_L2_CACHE
bool "Broadcom mobile SoC level 2 cache support"
depends on ARCH_BCM_281XX || ARCH_BCM_21664
default y
select CACHE_L2X0
select ARCH_BCM_MOBILE_SMC
config ARCH_BCM_MOBILE_SMC
bool
depends on ARCH_BCM_MOBILE
config ARCH_BCM_MOBILE_SMP
bool
depends on ARCH_BCM_MOBILE
select HAVE_ARM_SCU
select ARM_ERRATA_764369
help
SMP support for the BCM281XX, BCM21664 and BCM23550 SoC families.
Provided as an option so SMP support for SoCs of this type
can be disabled for an SMP-enabled kernel.
comment "Other Architectures"
config ARCH_BCM2835
bool "Broadcom BCM2835 family"
depends on ARCH_MULTI_V6 || ARCH_MULTI_V7
select GPIOLIB
select ARM_AMBA
select ARM_ERRATA_411920 if ARCH_MULTI_V6
select ARM_GIC if ARCH_MULTI_V7
select ZONE_DMA if ARCH_MULTI_V7
select ARM_TIMER_SP804
select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7
select BCM2835_TIMER
select PINCTRL
select PINCTRL_BCM2835
select MFD_CORE
help
This enables support for the Broadcom BCM2711 and BCM283x SoCs.
This SoC is used in the Raspberry Pi and Roku 2 devices.
config ARCH_BCM_53573
bool "Broadcom BCM53573 SoC series support"
depends on ARCH_MULTI_V7
select ARCH_BCM_IPROC
select HAVE_ARM_ARCH_TIMER
help
BCM53573 series is set of SoCs using ARM Cortex-A7 CPUs with wireless
embedded in the chipset.
This SoC line is mostly used in home routers and is some cheaper
alternative for Northstar family.
The base chip is BCM53573 and there are some packaging modifications
like BCM47189 and BCM47452.
config ARCH_BRCMSTB
bool "Broadcom BCM7XXX based boards"
depends on ARCH_MULTI_V7
select ARCH_HAS_RESET_CONTROLLER
select ARM_AMBA
select ARM_GIC
select ARM_GIC_V3
select ARM_ERRATA_798181 if SMP
select HAVE_ARM_ARCH_TIMER
select ZONE_DMA if ARM_LPAE
select SOC_BRCMSTB
select SOC_BUS
select PINCTRL
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.
menuconfig ARCH_BCMBCA
bool "Broadcom Broadband Carrier Access (BCA) origin SoC"
depends on ARCH_MULTI_V7
select ARM_AMBA
select ARM_GIC
select HAVE_ARM_ARCH_TIMER
help
Say Y if you intend to run the kernel on a Broadcom Broadband ARM-based
BCA chipset.
This enables support for Broadcom BCA ARM-based broadband chipsets,
including the DSL, PON and Wireless family of chips.
comment "BCMBCA sub platforms"
if ARCH_BCMBCA
config ARCH_BCMBCA_CORTEXA7
bool "Cortex-A7 SoCs"
help
Say Y if you intend to run the kernel on a Broadcom Broadband ARM A7
based chipset.
This enables support for Broadcom BCA ARM A7 broadband chipsets,
including various DSL, PON and Wireless family of chips.
config ARCH_BCMBCA_CORTEXA9
bool "Cortex-A9 SoCS"
select ARM_ERRATA_754322
select ARM_ERRATA_764369 if SMP
select ARCH_HAS_RESET_CONTROLLER
select ARM_GLOBAL_TIMER
select CACHE_L2X0
select HAVE_ARM_TWD if SMP
select HAVE_ARM_SCU if SMP
help
Say Y if you intend to run the kernel on a Broadcom Broadband ARM A9
based BCA chipset.
This enables support for Broadcom BCA ARM A9 broadband chipset. Currently
only DSL chip BCM63138.
config ARCH_BCMBCA_BRAHMAB15
bool "Brahma-B15 SoCs"
select ARM_ERRATA_798181 if SMP
help
Say Y if you intend to run the kernel on a Broadcom Broadband ARM B15
based BCA chipset.
This enables support for Broadcom BCA ARM B15 broadband chipset. Currently
only DSL chip BCM63148.
endif
endif
+63
View File
@@ -0,0 +1,63 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Copyright (C) 2012-2015 Broadcom Corporation
#
# Cygnus
obj-$(CONFIG_ARCH_BCM_CYGNUS) += bcm_cygnus.o
# Hurricane 2
obj-$(CONFIG_ARCH_BCM_HR2) += bcm_hr2.o
# Northstar Plus
obj-$(CONFIG_ARCH_BCM_NSP) += bcm_nsp.o
ifeq ($(CONFIG_ARCH_BCM_NSP),y)
obj-$(CONFIG_SMP) += platsmp.o
endif
# BCM281XX
obj-$(CONFIG_ARCH_BCM_281XX) += board_bcm281xx.o
# BCM21664
obj-$(CONFIG_ARCH_BCM_21664) += board_bcm21664.o
# BCM23550
obj-$(CONFIG_ARCH_BCM_23550) += board_bcm23550.o
# BCM281XX, BCM21664 and BCM23550 SMP support
obj-$(CONFIG_ARCH_BCM_MOBILE_SMP) += platsmp.o
# BCM281XX and BCM21664 L2 cache control
obj-$(CONFIG_ARCH_BCM_MOBILE_L2_CACHE) += kona_l2_cache.o
# Support for secure monitor traps
obj-$(CONFIG_ARCH_BCM_MOBILE_SMC) += bcm_kona_smc.o
CFLAGS_REMOVE_bcm_kona_smc.o += $(CC_FLAGS_FTRACE)
# BCM2835
ifeq ($(CONFIG_ARCH_BCM2835),y)
obj-y += board_bcm2835.o
obj-y += bcm2711.o
ifeq ($(CONFIG_ARM),y)
obj-$(CONFIG_SMP) += platsmp.o
endif
endif
# BCM5301X
obj-$(CONFIG_ARCH_BCM_5301X) += bcm_5301x.o
ifeq ($(CONFIG_ARCH_BCM_5301X),y)
obj-$(CONFIG_SMP) += platsmp.o
endif
ifeq ($(CONFIG_ARCH_BRCMSTB),y)
CFLAGS_platsmp-brcmstb.o += -march=armv7-a
obj-y += brcmstb.o
obj-$(CONFIG_SMP) += platsmp-brcmstb.o
endif
# BCMBCA
ifeq ($(CONFIG_ARCH_BCMBCA),y)
obj-$(CONFIG_DEBUG_BCMBCA) += board_bcmbca.o
obj-$(CONFIG_SMP) += bcm63xx_smp.o bcm63xx_pmb.o
endif
+25
View File
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2019 Stefan Wahren
*/
#include <linux/of_address.h>
#include <asm/mach/arch.h>
#include "platsmp.h"
static const char * const bcm2711_compat[] = {
#ifdef CONFIG_ARCH_MULTI_V7
"brcm,bcm2711",
#endif
NULL
};
DT_MACHINE_START(BCM2711, "BCM2711")
#ifdef CONFIG_ZONE_DMA
.dma_zone_size = SZ_1G,
#endif
.dt_compat = bcm2711_compat,
.smp = smp_ops(bcm2836_smp_ops),
MACHINE_END
+215
View File
@@ -0,0 +1,215 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Broadcom BCM63138 PMB initialization for secondary CPU(s)
*
* Copyright (C) 2015 Broadcom Corporation
* Author: Florian Fainelli <f.fainelli@gmail.com>
*/
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/spinlock.h>
#include <linux/reset/bcm63xx_pmb.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include "bcm63xx_smp.h"
/* ARM Control register definitions */
#define CORE_PWR_CTRL_SHIFT 0
#define CORE_PWR_CTRL_MASK 0x3
#define PLL_PWR_ON BIT(8)
#define PLL_LDO_PWR_ON BIT(9)
#define PLL_CLAMP_ON BIT(10)
#define CPU_RESET_N(x) BIT(13 + (x))
#define NEON_RESET_N BIT(15)
#define PWR_CTRL_STATUS_SHIFT 28
#define PWR_CTRL_STATUS_MASK 0x3
#define PWR_DOWN_SHIFT 30
#define PWR_DOWN_MASK 0x3
/* CPU Power control register definitions */
#define MEM_PWR_OK BIT(0)
#define MEM_PWR_ON BIT(1)
#define MEM_CLAMP_ON BIT(2)
#define MEM_PWR_OK_STATUS BIT(4)
#define MEM_PWR_ON_STATUS BIT(5)
#define MEM_PDA_SHIFT 8
#define MEM_PDA_MASK 0xf
#define MEM_PDA_CPU_MASK 0x1
#define MEM_PDA_NEON_MASK 0xf
#define CLAMP_ON BIT(15)
#define PWR_OK_SHIFT 16
#define PWR_OK_MASK 0xf
#define PWR_ON_SHIFT 20
#define PWR_CPU_MASK 0x03
#define PWR_NEON_MASK 0x01
#define PWR_ON_MASK 0xf
#define PWR_OK_STATUS_SHIFT 24
#define PWR_OK_STATUS_MASK 0xf
#define PWR_ON_STATUS_SHIFT 28
#define PWR_ON_STATUS_MASK 0xf
#define ARM_CONTROL 0x30
#define ARM_PWR_CONTROL_BASE 0x34
#define ARM_PWR_CONTROL(x) (ARM_PWR_CONTROL_BASE + (x) * 0x4)
#define ARM_NEON_L2 0x3c
/* Perform a value write, then spin until the value shifted by
* shift is seen, masked with mask and is different from cond.
*/
static int bpcm_wr_rd_mask(void __iomem *master,
unsigned int addr, u32 off, u32 *val,
u32 shift, u32 mask, u32 cond)
{
int ret;
ret = bpcm_wr(master, addr, off, *val);
if (ret)
return ret;
do {
ret = bpcm_rd(master, addr, off, val);
if (ret)
return ret;
cpu_relax();
} while (((*val >> shift) & mask) != cond);
return ret;
}
/* Global lock to serialize accesses to the PMB registers while we
* are bringing up the secondary CPU
*/
static DEFINE_SPINLOCK(pmb_lock);
static int bcm63xx_pmb_get_resources(struct device_node *dn,
void __iomem **base,
unsigned int *cpu,
unsigned int *addr)
{
struct of_phandle_args args;
int ret;
*cpu = of_get_cpu_hwid(dn, 0);
if (*cpu == ~0U) {
pr_err("CPU is missing a reg node\n");
return -ENODEV;
}
ret = of_parse_phandle_with_args(dn, "resets", "#reset-cells",
0, &args);
if (ret) {
pr_err("CPU is missing a resets phandle\n");
return ret;
}
if (args.args_count != 2) {
pr_err("reset-controller does not conform to reset-cells\n");
return -EINVAL;
}
*base = of_iomap(args.np, 0);
if (!*base) {
pr_err("failed remapping PMB register\n");
return -ENOMEM;
}
/* We do not need the number of zones */
*addr = args.args[0];
return 0;
}
int bcm63xx_pmb_power_on_cpu(struct device_node *dn)
{
void __iomem *base;
unsigned int cpu, addr;
unsigned long flags;
u32 val, ctrl;
int ret;
ret = bcm63xx_pmb_get_resources(dn, &base, &cpu, &addr);
if (ret)
return ret;
/* We would not know how to enable a third and greater CPU */
WARN_ON(cpu > 1);
spin_lock_irqsave(&pmb_lock, flags);
/* Check if the CPU is already on and save the ARM_CONTROL register
* value since we will use it later for CPU de-assert once done with
* the CPU-specific power sequence
*/
ret = bpcm_rd(base, addr, ARM_CONTROL, &ctrl);
if (ret)
goto out;
if (ctrl & CPU_RESET_N(cpu)) {
pr_info("PMB: CPU%d is already powered on\n", cpu);
ret = 0;
goto out;
}
/* Power on PLL */
ret = bpcm_rd(base, addr, ARM_PWR_CONTROL(cpu), &val);
if (ret)
goto out;
val |= (PWR_CPU_MASK << PWR_ON_SHIFT);
ret = bpcm_wr_rd_mask(base, addr, ARM_PWR_CONTROL(cpu), &val,
PWR_ON_STATUS_SHIFT, PWR_CPU_MASK, PWR_CPU_MASK);
if (ret)
goto out;
val |= (PWR_CPU_MASK << PWR_OK_SHIFT);
ret = bpcm_wr_rd_mask(base, addr, ARM_PWR_CONTROL(cpu), &val,
PWR_OK_STATUS_SHIFT, PWR_CPU_MASK, PWR_CPU_MASK);
if (ret)
goto out;
val &= ~CLAMP_ON;
ret = bpcm_wr(base, addr, ARM_PWR_CONTROL(cpu), val);
if (ret)
goto out;
/* Power on CPU<N> RAM */
val &= ~(MEM_PDA_MASK << MEM_PDA_SHIFT);
ret = bpcm_wr(base, addr, ARM_PWR_CONTROL(cpu), val);
if (ret)
goto out;
val |= MEM_PWR_ON;
ret = bpcm_wr_rd_mask(base, addr, ARM_PWR_CONTROL(cpu), &val,
0, MEM_PWR_ON_STATUS, MEM_PWR_ON_STATUS);
if (ret)
goto out;
val |= MEM_PWR_OK;
ret = bpcm_wr_rd_mask(base, addr, ARM_PWR_CONTROL(cpu), &val,
0, MEM_PWR_OK_STATUS, MEM_PWR_OK_STATUS);
if (ret)
goto out;
val &= ~MEM_CLAMP_ON;
ret = bpcm_wr(base, addr, ARM_PWR_CONTROL(cpu), val);
if (ret)
goto out;
/* De-assert CPU reset */
ctrl |= CPU_RESET_N(cpu);
ret = bpcm_wr(base, addr, ARM_CONTROL, ctrl);
out:
spin_unlock_irqrestore(&pmb_lock, flags);
iounmap(base);
return ret;
}
+168
View File
@@ -0,0 +1,168 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Broadcom BCM63138 DSL SoCs SMP support code
*
* Copyright (C) 2015, Broadcom Corporation
*/
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <asm/cacheflush.h>
#include <asm/smp_scu.h>
#include <asm/smp_plat.h>
#include <asm/vfp.h>
#include "bcm63xx_smp.h"
/* Size of mapped Cortex A9 SCU address space */
#define CORTEX_A9_SCU_SIZE 0x58
/*
* 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;
unsigned int i, ncores;
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\n");
return -ENOENT;
}
scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE);
if (!scu_base) {
pr_err("failed to remap config base (%lu/%u) for SCU\n",
config_base, CORTEX_A9_SCU_SIZE);
return -ENOMEM;
}
scu_enable(scu_base);
ncores = scu_base ? scu_get_core_count(scu_base) : 1;
if (ncores > nr_cpu_ids) {
pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
ncores, nr_cpu_ids);
ncores = nr_cpu_ids;
}
/* The BCM63138 SoC has two Cortex-A9 CPUs, CPU0 features a complete
* and fully functional VFP unit that can be used, but CPU1 does not.
* Since we will not be able to trap kernel-mode NEON to force
* migration to CPU0, just do not advertise VFP support at all.
*
* This will make vfp_init bail out and do not attempt to use VFP at
* all, for kernel-mode NEON, we do not want to introduce any
* conditionals in hot-paths, so we just restrict the system to UP.
*/
#ifdef CONFIG_VFP
if (ncores > 1) {
pr_warn("SMP: secondary CPUs lack VFP unit, disabling VFP\n");
vfp_disable();
#ifdef CONFIG_KERNEL_MODE_NEON
WARN(1, "SMP: kernel-mode NEON enabled, restricting to UP\n");
ncores = 1;
#endif
}
#endif
for (i = 0; i < ncores; i++)
set_cpu_possible(i, true);
iounmap(scu_base); /* That's the last we'll need of this */
return 0;
}
static const struct of_device_id bcm63138_bootlut_ids[] = {
{ .compatible = "brcm,bcm63138-bootlut", },
{ /* sentinel */ },
};
#define BOOTLUT_RESET_VECT 0x20
static int bcm63138_smp_boot_secondary(unsigned int cpu,
struct task_struct *idle)
{
void __iomem *bootlut_base;
struct device_node *dn;
int ret = 0;
u32 val;
dn = of_find_matching_node(NULL, bcm63138_bootlut_ids);
if (!dn) {
pr_err("SMP: unable to find bcm63138 boot LUT node\n");
return -ENODEV;
}
bootlut_base = of_iomap(dn, 0);
of_node_put(dn);
if (!bootlut_base) {
pr_err("SMP: unable to remap boot LUT base register\n");
return -ENOMEM;
}
/* Locate the secondary CPU node */
dn = of_get_cpu_node(cpu, NULL);
if (!dn) {
pr_err("SMP: failed to locate secondary CPU%d node\n", cpu);
ret = -ENODEV;
goto out;
}
/* Write the secondary init routine to the BootLUT reset vector */
val = __pa_symbol(secondary_startup);
writel_relaxed(val, bootlut_base + BOOTLUT_RESET_VECT);
/* Power up the core, will jump straight to its reset vector when we
* return
*/
ret = bcm63xx_pmb_power_on_cpu(dn);
of_node_put(dn);
out:
iounmap(bootlut_base);
return ret;
}
static void __init bcm63138_smp_prepare_cpus(unsigned int max_cpus)
{
int ret;
ret = scu_a9_enable();
if (ret) {
pr_warn("SMP: Cortex-A9 SCU setup failed\n");
return;
}
}
static const struct smp_operations bcm63138_smp_ops __initconst = {
.smp_prepare_cpus = bcm63138_smp_prepare_cpus,
.smp_boot_secondary = bcm63138_smp_boot_secondary,
};
CPU_METHOD_OF_DECLARE(bcm63138_smp, "brcm,bcm63138", &bcm63138_smp_ops);
@@ -0,0 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __BCM63XX_SMP_H
#define __BCM63XX_SMP_H
struct device_node;
extern int bcm63xx_pmb_power_on_cpu(struct device_node *dn);
#endif /* __BCM63XX_SMP_H */
+48
View File
@@ -0,0 +1,48 @@
/*
* Broadcom BCM470X / BCM5301X ARM platform code.
*
* Copyright 2013 Hauke Mehrtens <hauke@hauke-m.de>
*
* Licensed under the GNU/GPL. See COPYING for details.
*/
#include <asm/mach/arch.h>
#include <asm/siginfo.h>
#include <asm/signal.h>
#define FSR_EXTERNAL (1 << 12)
#define FSR_READ (0 << 10)
#define FSR_IMPRECISE 0x0406
static const char *const bcm5301x_dt_compat[] __initconst = {
"brcm,bcm4708",
NULL,
};
static int bcm5301x_abort_handler(unsigned long addr, unsigned int fsr,
struct pt_regs *regs)
{
/*
* We want to ignore aborts forwarded from the PCIe bus that are
* expected and shouldn't really be passed by the PCIe controller.
* The biggest disadvantage is the same FSR code may be reported when
* reading non-existing APB register and we shouldn't ignore that.
*/
if (fsr == (FSR_EXTERNAL | FSR_READ | FSR_IMPRECISE))
return 0;
return 1;
}
static void __init bcm5301x_init_early(void)
{
hook_fault_code(16 + 6, bcm5301x_abort_handler, SIGBUS, BUS_OBJERR,
"imprecise external abort");
}
DT_MACHINE_START(BCM5301X, "BCM5301X")
.l2c_aux_val = 0,
.l2c_aux_mask = ~0,
.dt_compat = bcm5301x_dt_compat,
.init_early = bcm5301x_init_early,
MACHINE_END
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (C) 2014 Broadcom Corporation
#include <asm/mach/arch.h>
static const char * const bcm_cygnus_dt_compat[] __initconst = {
"brcm,cygnus",
NULL,
};
DT_MACHINE_START(BCM_CYGNUS_DT, "Broadcom Cygnus SoC")
.l2c_aux_val = 0,
.l2c_aux_mask = ~0,
.dt_compat = bcm_cygnus_dt_compat,
MACHINE_END
+15
View File
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (C) 2017 Broadcom
#include <asm/mach/arch.h>
static const char * const bcm_hr2_dt_compat[] __initconst = {
"brcm,hr2",
NULL,
};
DT_MACHINE_START(BCM_HR2_DT, "Broadcom Hurricane 2 SoC")
.l2c_aux_val = 0,
.l2c_aux_mask = ~0,
.dt_compat = bcm_hr2_dt_compat,
MACHINE_END
@@ -0,0 +1,158 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (C) 2013 Broadcom Corporation
#include <linux/smp.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <asm/cacheflush.h>
#include <linux/of_address.h>
#include "bcm_kona_smc.h"
static u32 bcm_smc_buffer_phys; /* physical address */
static void __iomem *bcm_smc_buffer; /* virtual address */
struct bcm_kona_smc_data {
unsigned service_id;
unsigned arg0;
unsigned arg1;
unsigned arg2;
unsigned arg3;
unsigned result;
};
static const struct of_device_id bcm_kona_smc_ids[] __initconst = {
{.compatible = "brcm,kona-smc"},
{.compatible = "bcm,kona-smc"}, /* deprecated name */
{},
};
/* Map in the args buffer area */
int __init bcm_kona_smc_init(void)
{
struct device_node *node;
struct resource res;
int ret;
/* Read buffer addr and size from the device tree node */
node = of_find_matching_node(NULL, bcm_kona_smc_ids);
if (!node)
return -ENODEV;
ret = of_address_to_resource(node, 0, &res);
of_node_put(node);
if (ret)
return -EINVAL;
bcm_smc_buffer = ioremap(res.start, resource_size(&res));
if (!bcm_smc_buffer)
return -ENOMEM;
bcm_smc_buffer_phys = res.start;
pr_info("Kona Secure API initialized\n");
return 0;
}
/*
* int bcm_kona_do_smc(u32 service_id, u32 buffer_addr)
*
* Only core 0 can run the secure monitor code. If an "smc" request
* is initiated on a different core it must be redirected to core 0
* for execution. We rely on the caller to handle this.
*
* Each "smc" request supplies a service id and the address of a
* buffer containing parameters related to the service to be
* performed. A flags value defines the behavior of the level 2
* cache and interrupt handling while the secure monitor executes.
*
* Parameters to the "smc" request are passed in r4-r6 as follows:
* r4 service id
* r5 flags (SEC_ROM_*)
* r6 physical address of buffer with other parameters
*
* Execution of an "smc" request produces two distinct results.
*
* First, the secure monitor call itself (regardless of the specific
* service request) can succeed, or can produce an error. When an
* "smc" request completes this value is found in r12; it should
* always be SEC_EXIT_NORMAL.
*
* In addition, the particular service performed produces a result.
* The values that should be expected depend on the service. We
* therefore return this value to the caller, so it can handle the
* request result appropriately. This result value is found in r0
* when the "smc" request completes.
*/
static int bcm_kona_do_smc(u32 service_id, u32 buffer_phys)
{
register u32 ip asm("ip"); /* Also called r12 */
register u32 r0 asm("r0");
register u32 r4 asm("r4");
register u32 r5 asm("r5");
register u32 r6 asm("r6");
r4 = service_id;
r5 = 0x3; /* Keep IRQ and FIQ off in SM */
r6 = buffer_phys;
asm volatile (
/* Make sure we got the registers we want */
__asmeq("%0", "ip")
__asmeq("%1", "r0")
__asmeq("%2", "r4")
__asmeq("%3", "r5")
__asmeq("%4", "r6")
".arch_extension sec\n"
" smc #0\n"
: "=r" (ip), "=r" (r0)
: "r" (r4), "r" (r5), "r" (r6)
: "r1", "r2", "r3", "r7", "lr");
BUG_ON(ip != SEC_EXIT_NORMAL);
return r0;
}
/* __bcm_kona_smc() should only run on CPU 0, with pre-emption disabled */
static void __bcm_kona_smc(void *info)
{
struct bcm_kona_smc_data *data = info;
u32 __iomem *args = bcm_smc_buffer;
BUG_ON(smp_processor_id() != 0);
BUG_ON(!args);
/* Copy the four 32 bit argument values into the bounce area */
writel_relaxed(data->arg0, args++);
writel_relaxed(data->arg1, args++);
writel_relaxed(data->arg2, args++);
writel(data->arg3, args);
/* Flush caches for input data passed to Secure Monitor */
flush_cache_all();
/* Trap into Secure Monitor and record the request result */
data->result = bcm_kona_do_smc(data->service_id, bcm_smc_buffer_phys);
}
unsigned bcm_kona_smc(unsigned service_id, unsigned arg0, unsigned arg1,
unsigned arg2, unsigned arg3)
{
struct bcm_kona_smc_data data;
data.service_id = service_id;
data.arg0 = arg0;
data.arg1 = arg1;
data.arg2 = arg2;
data.arg3 = arg3;
data.result = 0;
/*
* Due to a limitation of the secure monitor, we must use the SMP
* infrastructure to forward all secure monitor calls to Core 0.
*/
smp_call_function_single(0, __bcm_kona_smc, &data, 1);
return data.result;
}
@@ -0,0 +1,22 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (C) 2013 Broadcom Corporation */
#ifndef BCM_KONA_SMC_H
#define BCM_KONA_SMC_H
#include <linux/types.h>
/* Broadcom Secure Service API service IDs, return codes, and exit codes */
#define SSAPI_ENABLE_L2_CACHE 0x01000002
#define SEC_ROM_RET_OK 0x00000001
#define SEC_EXIT_NORMAL 0x1
extern int __init bcm_kona_smc_init(void);
extern unsigned bcm_kona_smc(unsigned service_id,
unsigned arg0,
unsigned arg1,
unsigned arg2,
unsigned arg3);
#endif /* BCM_KONA_SMC_H */
+15
View File
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (C) 2015 Broadcom Corporation
#include <asm/mach/arch.h>
static const char *const bcm_nsp_dt_compat[] __initconst = {
"brcm,nsp",
NULL,
};
DT_MACHINE_START(NSP_DT, "Broadcom Northstar Plus SoC")
.l2c_aux_val = 0,
.l2c_aux_mask = ~0,
.dt_compat = bcm_nsp_dt_compat,
MACHINE_END
@@ -0,0 +1,21 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (C) 2014 Broadcom Corporation
#include <asm/mach/arch.h>
#include "kona_l2_cache.h"
static void __init bcm21664_init(void)
{
kona_l2_cache_init();
}
static const char * const bcm21664_dt_compat[] = {
"brcm,bcm21664",
NULL,
};
DT_MACHINE_START(BCM21664_DT, "BCM21664 Broadcom Application Processor")
.init_machine = bcm21664_init,
.dt_compat = bcm21664_dt_compat,
MACHINE_END
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (C) 2016 Broadcom
#include <asm/mach/arch.h>
static const char * const bcm23550_dt_compat[] = {
"brcm,bcm23550",
NULL,
};
DT_MACHINE_START(BCM23550_DT, "BCM23550 Broadcom Application Processor")
.dt_compat = bcm23550_dt_compat,
MACHINE_END
@@ -0,0 +1,63 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (C) 2012-2014 Broadcom Corporation
#include <linux/clocksource.h>
#include <linux/of_address.h>
#include <asm/mach/arch.h>
#include "kona_l2_cache.h"
#define SECWDOG_OFFSET 0x00000000
#define SECWDOG_RESERVED_MASK 0xe2000000
#define SECWDOG_WD_LOAD_FLAG_MASK 0x10000000
#define SECWDOG_EN_MASK 0x08000000
#define SECWDOG_SRSTEN_MASK 0x04000000
#define SECWDOG_CLKS_SHIFT 20
#define SECWDOG_COUNT_SHIFT 0
static void bcm281xx_restart(enum reboot_mode mode, const char *cmd)
{
uint32_t val;
void __iomem *base;
struct device_node *np_wdog;
np_wdog = of_find_compatible_node(NULL, NULL, "brcm,kona-wdt");
if (!np_wdog) {
pr_emerg("Couldn't find brcm,kona-wdt\n");
return;
}
base = of_iomap(np_wdog, 0);
of_node_put(np_wdog);
if (!base) {
pr_emerg("Couldn't map brcm,kona-wdt\n");
return;
}
/* Enable watchdog with short timeout (244us). */
val = readl(base + SECWDOG_OFFSET);
val &= SECWDOG_RESERVED_MASK | SECWDOG_WD_LOAD_FLAG_MASK;
val |= SECWDOG_EN_MASK | SECWDOG_SRSTEN_MASK |
(0x15 << SECWDOG_CLKS_SHIFT) |
(0x8 << SECWDOG_COUNT_SHIFT);
writel(val, base + SECWDOG_OFFSET);
/* Wait for reset */
while (1);
}
static void __init bcm281xx_init(void)
{
kona_l2_cache_init();
}
static const char * const bcm281xx_dt_compat[] = {
"brcm,bcm11351", /* Have to use the first number upstreamed */
NULL,
};
DT_MACHINE_START(BCM281XX_DT, "BCM281xx Broadcom Application Processor")
.init_machine = bcm281xx_init,
.restart = bcm281xx_restart,
.dt_compat = bcm281xx_dt_compat,
MACHINE_END
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2010 Broadcom
*/
#include <linux/init.h>
#include <linux/irqchip.h>
#include <linux/of_address.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include "platsmp.h"
static const char * const bcm2835_compat[] = {
#ifdef CONFIG_ARCH_MULTI_V6
"brcm,bcm2835",
#endif
#ifdef CONFIG_ARCH_MULTI_V7
"brcm,bcm2836",
"brcm,bcm2837",
#endif
NULL
};
DT_MACHINE_START(BCM2835, "BCM2835")
.dt_compat = bcm2835_compat,
.smp = smp_ops(bcm2836_smp_ops),
MACHINE_END
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (C) 2024 Linus Walleij <linus.walleij@linaro.org>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
/* This is needed for LL-debug/earlyprintk/debug-macro.S */
static struct map_desc bcmbca_io_desc[] __initdata = {
{
.virtual = CONFIG_DEBUG_UART_VIRT,
.pfn = __phys_to_pfn(CONFIG_DEBUG_UART_PHYS),
.length = SZ_4K,
.type = MT_DEVICE,
},
};
static void __init bcmbca_map_io(void)
{
iotable_init(bcmbca_io_desc, ARRAY_SIZE(bcmbca_io_desc));
}
static const char * const bcmbca_dt_compat[] = {
/* TODO: Add other BCMBCA SoCs here to get debug UART support */
"brcm,bcm6846",
NULL,
};
DT_MACHINE_START(BCMBCA_DT, "BCMBCA Broadband Access Processors")
.map_io = bcmbca_map_io,
.dt_compat = bcmbca_dt_compat,
MACHINE_END
+34
View File
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (C) 2013-2014 Broadcom Corporation
#include <linux/init.h>
#include <linux/irqchip.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
/*
* Storage for debug-macro.S's state.
*
* This must be in .data not .bss so that it gets initialized each time the
* kernel is loaded. The data is declared here rather than debug-macro.S so
* that multiple inclusions of debug-macro.S point at the same data.
*/
u32 brcmstb_uart_config[3] = {
/* Debug UART initialization required */
1,
/* Debug UART physical address */
0,
/* Debug UART virtual address */
0,
};
static const char *const brcmstb_match[] __initconst = {
"brcm,bcm7445",
"brcm,brcmstb",
NULL
};
DT_MACHINE_START(BRCMSTB, "Broadcom STB (Flattened Device Tree)")
.dt_compat = brcmstb_match,
MACHINE_END
@@ -0,0 +1,38 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (C) 2012-2014 Broadcom Corporation
#include <linux/init.h>
#include <linux/printk.h>
#include <asm/hardware/cache-l2x0.h>
#include "bcm_kona_smc.h"
#include "kona_l2_cache.h"
void __init kona_l2_cache_init(void)
{
unsigned int result;
int ret;
ret = bcm_kona_smc_init();
if (ret) {
pr_info("Secure API not available (%d). Skipping L2 init.\n",
ret);
return;
}
result = bcm_kona_smc(SSAPI_ENABLE_L2_CACHE, 0, 0, 0, 0);
if (result != SEC_ROM_RET_OK) {
pr_err("Secure Monitor call failed (%u)! Skipping L2 init.\n",
result);
return;
}
/*
* The aux_val and aux_mask have no effect since L2 cache is already
* enabled. Pass 0s for aux_val and 1s for aux_mask for default value.
*/
ret = l2x0_of_init(0, ~0);
if (ret)
pr_err("Couldn't enable L2 cache: %d\n", ret);
}
@@ -0,0 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (C) 2012-2014 Broadcom Corporation */
#ifdef CONFIG_ARCH_BCM_MOBILE_L2_CACHE
void kona_l2_cache_init(void);
#else
#define kona_l2_cache_init() ((void)0)
#endif
@@ -0,0 +1,363 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Broadcom STB CPU SMP and hotplug support for ARM
*
* Copyright (C) 2013-2014 Broadcom Corporation
*/
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/jiffies.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/printk.h>
#include <linux/regmap.h>
#include <linux/smp.h>
#include <linux/mfd/syscon.h>
#include <asm/cacheflush.h>
#include <asm/cp15.h>
#include <asm/mach-types.h>
#include <asm/smp_plat.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
/*
* We must quiesce a dying CPU before it can be killed by the boot CPU. Because
* one or more cache may be disabled, we must flush to ensure coherency. We
* cannot use traditional completion structures or spinlocks as they rely on
* coherency.
*/
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)
{
dmb();
per_cpu(per_cpu_sw_state, cpu) = val;
sync_cache_w(SHIFT_PERCPU_PTR(&per_cpu_sw_state, per_cpu_offset(cpu)));
}
#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_set(unsigned int cpu, u32 val, u32 mask)
{
void __iomem *base = pwr_ctrl_get_base(cpu);
writel((readl(base) & mask) | val, base);
}
static void pwr_ctrl_clr(unsigned int cpu, u32 val, u32 mask)
{
void __iomem *base = pwr_ctrl_get_base(cpu);
writel((readl(base) & mask) & ~val, base);
}
#define POLL_TMOUT_MS 500
static int pwr_ctrl_wait_tmout(unsigned int cpu, u32 set, u32 mask)
{
const unsigned long timeo = jiffies + msecs_to_jiffies(POLL_TMOUT_MS);
u32 tmp;
do {
tmp = pwr_ctrl_rd(cpu) & mask;
if (!set == !tmp)
return 0;
} while (time_before(jiffies, timeo));
tmp = pwr_ctrl_rd(cpu) & mask;
if (!set == !tmp)
return 0;
return -ETIMEDOUT;
}
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)
{
/* Mark this CPU as "up" */
per_cpu_sw_state_wr(cpu, 1);
/*
* Set the reset vector to point to the secondary_startup
* routine
*/
cpu_set_boot_addr(cpu, __pa_symbol(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.
*/
pwr_ctrl_set(cpu, ZONE_MAN_ISO_CNTL_MASK, 0xffffff00);
pwr_ctrl_set(cpu, ZONE_MANUAL_CONTROL_MASK, -1);
pwr_ctrl_set(cpu, ZONE_RESERVED_1_MASK, -1);
pwr_ctrl_set(cpu, ZONE_MAN_MEM_PWR_MASK, -1);
if (pwr_ctrl_wait_tmout(cpu, 1, ZONE_MEM_PWR_STATE_MASK))
panic("ZONE_MEM_PWR_STATE_MASK set timeout");
pwr_ctrl_set(cpu, ZONE_MAN_CLKEN_MASK, -1);
if (pwr_ctrl_wait_tmout(cpu, 1, ZONE_DPG_PWR_STATE_MASK))
panic("ZONE_DPG_PWR_STATE_MASK set timeout");
pwr_ctrl_clr(cpu, ZONE_MAN_ISO_CNTL_MASK, -1);
pwr_ctrl_set(cpu, ZONE_MAN_RESET_CNTL_MASK, -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);
per_cpu_sw_state_wr(cpu, 0);
/* Sit and wait to die */
wfi();
/* We should never get here... */
while (1)
;
}
static int brcmstb_cpu_kill(u32 cpu)
{
/*
* Ordinarily, the hardware forbids power-down of CPU0 (which is good
* because it is the boot CPU), but this is not true when using BPCM
* manual mode. Consequently, we must avoid turning off CPU0 here to
* ensure that TI2C master reset will work.
*/
if (cpu == 0) {
pr_warn("SMP: refusing to power off CPU0\n");
return 1;
}
while (per_cpu_sw_state_rd(cpu))
;
pwr_ctrl_set(cpu, ZONE_MANUAL_CONTROL_MASK, -1);
pwr_ctrl_clr(cpu, ZONE_MAN_RESET_CNTL_MASK, -1);
pwr_ctrl_clr(cpu, ZONE_MAN_CLKEN_MASK, -1);
pwr_ctrl_set(cpu, ZONE_MAN_ISO_CNTL_MASK, -1);
pwr_ctrl_clr(cpu, ZONE_MAN_MEM_PWR_MASK, -1);
if (pwr_ctrl_wait_tmout(cpu, 0, ZONE_MEM_PWR_STATE_MASK))
panic("ZONE_MEM_PWR_STATE_MASK clear timeout");
pwr_ctrl_clr(cpu, ZONE_RESERVED_1_MASK, -1);
if (pwr_ctrl_wait_tmout(cpu, 0, ZONE_DPG_PWR_STATE_MASK))
panic("ZONE_DPG_PWR_STATE_MASK clear timeout");
/* Flush pipeline before resetting CPU */
mb();
/* 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:
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:
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)
goto out_put_node;
rc = setup_hifcont_regs(np);
if (rc)
goto out_put_node;
out_put_node:
of_node_put(np);
}
static int brcmstb_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
/* Missing the brcm,brcmstb-smpboot DT node? */
if (!cpubiuctrl_block || !hif_cont_block)
return -ENODEV;
/* 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);
return 0;
}
static const struct smp_operations brcmstb_smp_ops __initconst = {
.smp_prepare_cpus = brcmstb_cpu_ctrl_setup,
.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);
+339
View File
@@ -0,0 +1,339 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2014-2015 Broadcom Corporation
* Copyright 2014 Linaro Limited
*/
#include <linux/cpumask.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/irqchip/irq-bcm2836.h>
#include <linux/jiffies.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/sched.h>
#include <linux/sched/clock.h>
#include <linux/smp.h>
#include <asm/cacheflush.h>
#include <asm/smp.h>
#include <asm/smp_plat.h>
#include <asm/smp_scu.h>
#include "platsmp.h"
/* Size of mapped Cortex A9 SCU address space */
#define CORTEX_A9_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"
#define MPIDR_CPUID_BITMASK 0x3
/*
* 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\n");
return -ENOENT;
}
scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE);
if (!scu_base) {
pr_err("failed to remap config base (%lu/%u) for SCU\n",
config_base, CORTEX_A9_SCU_SIZE);
return -ENOMEM;
}
scu_enable(scu_base);
iounmap(scu_base); /* That's the last we'll need of this */
return 0;
}
static u32 secondary_boot_addr_for(unsigned int cpu)
{
u32 secondary_boot_addr = 0;
struct device_node *cpu_node = of_get_cpu_node(cpu, NULL);
if (!cpu_node) {
pr_err("Failed to find device tree node for CPU%u\n", cpu);
return 0;
}
if (of_property_read_u32(cpu_node,
OF_SECONDARY_BOOT,
&secondary_boot_addr))
pr_err("required secondary boot register not specified for CPU%u\n",
cpu);
of_node_put(cpu_node);
return secondary_boot_addr;
}
static int nsp_write_lut(unsigned int cpu)
{
void __iomem *sku_rom_lut;
phys_addr_t secondary_startup_phy;
const u32 secondary_boot_addr = secondary_boot_addr_for(cpu);
if (!secondary_boot_addr)
return -EINVAL;
sku_rom_lut = ioremap((phys_addr_t)secondary_boot_addr,
sizeof(phys_addr_t));
if (!sku_rom_lut) {
pr_warn("unable to ioremap SKU-ROM LUT register for cpu %u\n", cpu);
return -ENOMEM;
}
secondary_startup_phy = __pa_symbol(secondary_startup);
BUG_ON(secondary_startup_phy > (phys_addr_t)U32_MAX);
writel_relaxed(secondary_startup_phy, sku_rom_lut);
/* Ensure the write is visible to the secondary core */
smp_wmb();
iounmap(sku_rom_lut);
return 0;
}
static void __init bcm_smp_prepare_cpus(unsigned int max_cpus)
{
const cpumask_t only_cpu_0 = { CPU_BITS_CPU0 };
/* Enable the SCU on Cortex A9 based SoCs */
if (scu_a9_enable()) {
/* Update the CPU present map to reflect uniprocessor mode */
pr_warn("failed to enable A9 SCU - disabling SMP\n");
init_cpu_present(&only_cpu_0);
}
}
/*
* 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 kona_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;
const u32 secondary_boot_addr = secondary_boot_addr_for(cpu);
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_addr)
return -EINVAL;
boot_reg = ioremap((phys_addr_t)secondary_boot_addr,
sizeof(phys_addr_t));
if (!boot_reg) {
pr_err("unable to map boot register for cpu %u\n", cpu_id);
return -ENOMEM;
}
/*
* Secondary cores will start in secondary_startup(),
* defined in "arch/arm/kernel/head.S"
*/
boot_func = __pa_symbol(secondary_startup);
BUG_ON(boot_func & BOOT_ADDR_CPUID_MASK);
BUG_ON(boot_func > (phys_addr_t)U32_MAX);
/* The core to start is encoded in the low bits */
boot_val = (u32)boot_func | cpu_id;
writel_relaxed(boot_val, boot_reg);
sev();
/* The low bits will be cleared once the core has started */
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 -ENXIO;
}
/* Cluster Dormant Control command to bring CPU into a running state */
#define CDC_CMD 6
#define CDC_CMD_OFFSET 0
#define CDC_CMD_REG(cpu) (CDC_CMD_OFFSET + 4*(cpu))
/*
* BCM23550 has a Cluster Dormant Control block that keeps the core in
* idle state. A command needs to be sent to the block to bring the CPU
* into running state.
*/
static int bcm23550_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
void __iomem *cdc_base;
struct device_node *dn;
char *name;
int ret;
/* Make sure a CDC node exists before booting the
* secondary core.
*/
name = "brcm,bcm23550-cdc";
dn = of_find_compatible_node(NULL, NULL, name);
if (!dn) {
pr_err("unable to find cdc node\n");
return -ENODEV;
}
cdc_base = of_iomap(dn, 0);
of_node_put(dn);
if (!cdc_base) {
pr_err("unable to remap cdc base register\n");
return -ENOMEM;
}
/* Boot the secondary core */
ret = kona_boot_secondary(cpu, idle);
if (ret)
goto out;
/* Bring this CPU to RUN state so that nIRQ nFIQ
* signals are unblocked.
*/
writel_relaxed(CDC_CMD, cdc_base + CDC_CMD_REG(cpu));
out:
iounmap(cdc_base);
return ret;
}
static int nsp_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
int ret;
/*
* After wake up, secondary core branches to the startup
* address programmed at SKU ROM LUT location.
*/
ret = nsp_write_lut(cpu);
if (ret) {
pr_err("unable to write startup addr to SKU ROM LUT\n");
goto out;
}
/* Send a CPU wakeup interrupt to the secondary core */
arch_send_wakeup_ipi_mask(cpumask_of(cpu));
out:
return ret;
}
static int bcm2836_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
void __iomem *intc_base;
struct device_node *dn;
char *name;
name = "brcm,bcm2836-l1-intc";
dn = of_find_compatible_node(NULL, NULL, name);
if (!dn) {
pr_err("unable to find intc node\n");
return -ENODEV;
}
intc_base = of_iomap(dn, 0);
of_node_put(dn);
if (!intc_base) {
pr_err("unable to remap intc base register\n");
return -ENOMEM;
}
writel(virt_to_phys(secondary_startup),
intc_base + LOCAL_MAILBOX3_SET0 + 16 * cpu);
dsb(sy);
sev();
iounmap(intc_base);
return 0;
}
static const struct smp_operations kona_smp_ops __initconst = {
.smp_prepare_cpus = bcm_smp_prepare_cpus,
.smp_boot_secondary = kona_boot_secondary,
};
CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method",
&kona_smp_ops);
static const struct smp_operations bcm23550_smp_ops __initconst = {
.smp_boot_secondary = bcm23550_boot_secondary,
};
CPU_METHOD_OF_DECLARE(bcm_smp_bcm23550, "brcm,bcm23550",
&bcm23550_smp_ops);
static const struct smp_operations nsp_smp_ops __initconst = {
.smp_prepare_cpus = bcm_smp_prepare_cpus,
.smp_boot_secondary = nsp_boot_secondary,
};
CPU_METHOD_OF_DECLARE(bcm_smp_nsp, "brcm,bcm-nsp-smp", &nsp_smp_ops);
const struct smp_operations bcm2836_smp_ops __initconst = {
.smp_boot_secondary = bcm2836_boot_secondary,
};
CPU_METHOD_OF_DECLARE(bcm_smp_bcm2836, "brcm,bcm2836-smp", &bcm2836_smp_ops);
+6
View File
@@ -0,0 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2017 Stefan Wahren <stefan.wahren@i2se.com>
*/
extern const struct smp_operations bcm2836_smp_ops;